C模块可通过OpenResty的ngx_http_lua_shdict接口安全访问Lua定义的shared dict;需在nginx.conf中用lua_shared_dict声明,C代码调用ngx_http_lua_find_zone和ngx_http_lua_shdict_lookup读取数据,仅支持string/number类型,且须在worker进程请求上下文中操作。

在 OpenResty 环境中,Lua 代码可通过 resty.shared_dict 模块定义和操作共享内存字典(shared dict),而 C 模块(如用 Nginx C API 编写的模块)默认无法直接访问 Lua 的 shared dict。但通过 OpenResty 提供的 lua-resty-core 和底层 C API 集成机制,C 模块可以安全、高效地读取 Lua 定义的共享字典数据——关键在于复用 Nginx 内核的 ngx_http_upstream_shm_zone_t 机制,并借助 OpenResty 的 Lua VM 共享上下文完成绑定。
确认共享字典已在 Lua 层正确定义
Shared dict 必须由 Lua 层(通常是 init_by_lua* 或 http {} 块中的 lua_shared_dict 指令)预先声明,C 模块才能访问其底层共享内存区域:
-
必须使用
lua_shared_dict my_dict 10m;在 nginx.conf 中声明,不能仅靠 Lua 代码动态创建(如shared = require "resty.core.shdict".new("my_dict")不会注册到 Nginx 共享内存区) - 确保 dict 名称无特殊字符(只允许字母、数字、下划线),且大小写敏感
- 推荐在
http {}块中定义,避免因作用域问题导致 C 模块查找不到
在 C 模块中获取并访问 shared dict 的共享内存 zone
C 模块需调用 Nginx 核心函数定位已注册的 shared dict zone,再通过 OpenResty 的辅助宏安全读取数据:
- 使用
ngx_shared_memory_add()注册时同名的shm_zone可通过ngx_cycle->shared_memory链表遍历查找,或更可靠地:调用ngx_http_lua_find_zone()(来自ngx_http_lua_util.h)传入 dict 名字获取ngx_http_lua_shdict_ctx_t * - OpenResty 的
ngx_http_lua_shdict_ctx_t封装了底层ngx_slab_pool_t *和哈希表结构,支持原子读写;C 模块应使用其提供的ngx_http_lua_shdict_lookup()查找 key,再用ngx_http_lua_shdict_get_str_value()或ngx_http_lua_shdict_get_num_value()提取值 - 注意:所有操作必须在 worker 进程上下文中进行,不可在 master 进程或 init 阶段调用(此时 slab 尚未初始化)
典型 C 调用示例(简化版)
以下伪代码展示如何在 handler 钩子中读取名为 cache_dict 的 shared dict 中的字符串值:
- 包含必要头文件:
#include "ngx_http_lua_common.h"、"ngx_http_lua_shdict.h" - 在处理函数中:
ngx_http_lua_shdict_ctx_t *ctx; ngx_str_t dict_name = ngx_string("cache_dict"); ngx_str_t key = ngx_string("user:123"); ngx_str_t value; ctx = ngx_http_lua_find_zone(r->connection->log, &dict_name); if (!ctx || !ctx->shpool) { return NGX_ERROR; // 字典未找到或未就绪 } if (ngx_http_lua_shdict_lookup(ctx, &key, &value, NULL) == NGX_OK) { // value.data/value.len 即为 Lua 中 set("user:123", "Alice") 存入的值 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shared dict get: %V", &value); }
注意事项与避坑指南
实际集成中易出现以下问题,需提前规避:
-
版本兼容性:
ngx_http_lua_shdict_*接口在 OpenResty 1.19.3.2+ 中稳定公开,旧版本需自行解析ngx_http_lua_shdict_node_t结构,不推荐 - 数据类型限制:C 模块只能读取 Lua 以 string/number 类型存入的数据;table、function、cdata 等复杂类型无法直接还原,Lua 层应统一序列化为 JSON 或 msgpack 字符串
- 生命周期管理:shared dict 数据由 slab 分配器管理,C 模块无需 free;但 value 字符串指针指向共享内存,不可长期缓存或跨请求复用,应在当前请求周期内使用完毕
- 并发安全:OpenResty 的 shdict 实现本身是多 worker 安全的,C 模块调用其封装接口即自动获得原子性保障,无需额外加锁










