lolly/docs/lua-nginx-module/05-shdict.md
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

6.2 KiB

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 节点结构

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 值类型枚举

enum {
    SHDICT_TNIL     = 0,  /* 空值 */
    SHDICT_TBOOLEAN = 1,  /* 布尔值 */
    SHDICT_TNUMBER  = 3,  /* 数字 */
    SHDICT_TSTRING  = 4,  /* 字符串 */
    SHDICT_TLIST    = 5,  /* 列表 */
};

2.3 共享上下文

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
  • 示例:
    lua_shared_dict cache 10m;
    lua_shared_dict sessions 100m;
    lua_shared_dict counters 1m;
    

四、Lua API

4.1 获取字典对象

local dict = ngx.shared.cache

4.2 基础操作

dict:get(key)

获取值。

  • 参数: key (string)
  • 返回值: value, err 或 nil
  • 示例:
    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
  • 示例:
    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
  • 示例:
    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)

获取列表长度。

  • 示例:
    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 并发控制

使用互斥锁保护共享数据:

ngx_shmtx_lock(&ctx->shpool->mutex);
// 操作共享数据
ngx_shmtx_unlock(&ctx->shpool->mutex);

六、使用示例

6.1 简单缓存

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 分布式锁

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 限流计数

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