xfy 941c44b798 docs: 添加 Lua 嵌入分析文档
- 新增 lua-embed-analysis.md 技术分析文档
- 新增 lua-nginx-module 文档目录
- 更新 gitignore 允许跟踪 docs/lua-nginx-module/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 11:20:57 +08:00

333 lines
6.2 KiB
Markdown

# lua-nginx-module 共享内存字典 (shdict)
本文档详细说明 lua-nginx-module 的共享内存字典功能。
---
## 一、核心文件
| 文件 | 说明 |
|------|------|
| `src/ngx_http_lua_shdict.c` | shdict 核心实现 |
| `src/ngx_http_lua_shdict.h` | 数据结构定义 |
| `src/ngx_http_lua_directive.c` | 配置指令处理 |
---
## 二、数据结构
### 2.1 节点结构
```c
typedef struct {
u_char color; /* 红黑树颜色 */
uint8_t value_type; /* 值类型 */
u_short key_len; /* key 长度 */
uint32_t value_len; /* value 长度 */
uint64_t expires; /* 过期时间 (毫秒) */
ngx_queue_t queue; /* LRU 队列节点 */
uint32_t user_flags; /* 用户自定义标志 */
u_char data[1]; /* key + value 数据 */
} ngx_http_lua_shdict_node_t;
```
### 2.2 值类型枚举
```c
enum {
SHDICT_TNIL = 0, /* 空值 */
SHDICT_TBOOLEAN = 1, /* 布尔值 */
SHDICT_TNUMBER = 3, /* 数字 */
SHDICT_TSTRING = 4, /* 字符串 */
SHDICT_TLIST = 5, /* 列表 */
};
```
### 2.3 共享上下文
```c
typedef struct {
ngx_rbtree_t rbtree; /* 红黑树根 */
ngx_rbtree_node_t sentinel; /* 红黑树哨兵 */
ngx_queue_t lru_queue; /* LRU 队列头 */
} ngx_http_lua_shdict_shctx_t;
typedef struct {
ngx_http_lua_shdict_shctx_t *sh; /* 共享上下文 */
ngx_slab_pool_t *shpool; /* slab 分配器 */
ngx_str_t name; /* 字典名称 */
} ngx_http_lua_shdict_ctx_t;
```
---
## 三、配置
### `lua_shared_dict <name> <size>`
定义共享内存字典。
- **参数**:
- `name`: 字典名称
- `size`: 内存大小 (最小 8KB)
- **配置层级**: main
- **示例**:
```nginx
lua_shared_dict cache 10m;
lua_shared_dict sessions 100m;
lua_shared_dict counters 1m;
```
---
## 四、Lua API
### 4.1 获取字典对象
```lua
local dict = ngx.shared.cache
```
### 4.2 基础操作
#### `dict:get(key)`
获取值。
- **参数**: `key` (string)
- **返回值**: value, err 或 nil
- **示例**:
```lua
local val, err = ngx.shared.cache:get("user:123")
if val == nil and err then
ngx.log(ngx.ERR, "get failed: ", err)
end
```
#### `dict:get_stale(key)`
获取值(允许过期数据)。
#### `dict:set(key, value, exptime?, flags?)`
设置值。
- **参数**:
- `key` (string)
- `value` (string/number/boolean/nil)
- `exptime` (number, 可选): 过期时间秒数
- `flags` (number, 可选): 用户标志
- **返回值**: success, err, forcible
- **示例**:
```lua
local dict = ngx.shared.cache
local ok, err, forcible = dict:set("key", "value", 60)
if forcible then
ngx.log(ngx.WARN, "forced to evict old items")
end
```
#### `dict:safe_set(key, value, exptime?, flags?)`
安全设置值(不会淘汰有效项)。
#### `dict:add(key, value, exptime?, flags?)`
仅在 key 不存在时添加。
#### `dict:safe_add(key, value, exptime?, flags?)`
安全添加(不会淘汰有效项)。
#### `dict:replace(key, value, exptime?, flags?)`
仅在 key 存在时替换。
#### `dict:delete(key)`
删除 key。
### 4.3 数值操作
#### `dict:incr(key, value, init?)`
原子递增。
- **参数**:
- `key` (string)
- `value` (number): 增量
- `init` (number, 可选): key 不存在时的初始值
- **返回值**: new_value, err 或 nil
- **示例**:
```lua
local dict = ngx.shared.counters
local new_val, err = dict:incr("hits", 1, 0)
ngx.say("Hits: ", new_val)
```
### 4.4 列表操作
#### `dict:lpush(key, value)`
左侧推入列表。
#### `dict:rpush(key, value)`
右侧推入列表。
#### `dict:lpop(key)`
左侧弹出列表。
#### `dict:rpop(key)`
右侧弹出列表。
#### `dict:llen(key)`
获取列表长度。
- **示例**:
```lua
local dict = ngx.shared.queue
dict:rpush("jobs", "job1")
dict:rpush("jobs", "job2")
local job = dict:lpop("jobs") -- "job1"
local len = dict:llen("jobs") -- 1
```
### 4.5 过期管理
#### `dict:ttl(key)`
获取剩余 TTL。
- **返回值**: ttl, err 或 nil
#### `dict:expire(key, exptime)`
设置过期时间。
- **参数**:
- `key` (string)
- `exptime` (number): 秒数
- **返回值**: success, err
#### `dict:flush_all()`
标记所有项为过期。
#### `dict:flush_expired(max_count?)`
清除过期项。
- **参数**: `max_count` (number, 可选)
### 4.6 容量信息
#### `dict:capacity()`
获取总容量。
- **返回值**: number (bytes)
#### `dict:free_space()`
获取空闲空间。
- **返回值**: number (bytes)
#### `dict:get_keys(max_count?)`
获取所有 key。
- **参数**: `max_count` (number, 可选, 默认 1024)
- **返回值**: table of keys
---
## 五、内部实现
### 5.1 Slab 分配器
使用 Nginx 的 slab 分配器管理共享内存:
- `ngx_slab_alloc_locked()` / `ngx_slab_alloc()`
- `ngx_slab_free_locked()` / `ngx_slab_free()`
### 5.2 红黑树索引
用于快速查找:
- Key 哈希 → 红黑树节点
- 冲突处理:`ngx_memn2cmp` 比较实际 key
### 5.3 LRU 队列
实现最近最少使用淘汰:
- 新访问项移到队列头
- 淘汰时从队列尾移除
### 5.4 并发控制
使用互斥锁保护共享数据:
```c
ngx_shmtx_lock(&ctx->shpool->mutex);
// 操作共享数据
ngx_shmtx_unlock(&ctx->shpool->mutex);
```
---
## 六、使用示例
### 6.1 简单缓存
```lua
local function get_with_cache(key, fetch_func, ttl)
local dict = ngx.shared.cache
local value = dict:get(key)
if value then
return value
end
value = fetch_func()
dict:set(key, value, ttl)
return value
end
```
### 6.2 分布式锁
```lua
local function acquire_lock(lock_name, timeout, expiry)
local dict = ngx.shared.locks
local ok, err = dict:add(lock_name, 1, expiry)
if ok then
return true
end
return false, err
end
local function release_lock(lock_name)
local dict = ngx.shared.locks
dict:delete(lock_name)
end
```
### 6.3 限流计数
```lua
local function rate_limit(key, limit, window)
local dict = ngx.shared.limits
local count, err = dict:incr(key, 1, 0, window)
if count > limit then
return false -- 超限
end
return true
end
```