OpenResty 的 lua_shared_dict 通过 mmap 实现多 Worker 零拷贝共享内存,需在 http 块声明,命名大小写敏感、单位小写,单 key≤255 字节,value≤8MB;支持原子操作如 incr/get_set,但数据不持久、不跨机、无函数支持。

OpenResty 通过 lua_shared_dict 实现多 Worker 共享内存,本质是让所有 worker 进程映射到同一块内核级共享内存区域,无需网络、不走序列化、零上下文切换——所有读写都在 mmap 映射的物理内存中完成,由 Nginx 自旋锁保障原子性。
必须在 http 块中声明字典
这是硬性前提,位置错就启动失败:
-
lua_shared_dict只能在http{}块内使用,放在server、location或任意嵌套块中会报[emerg] "lua_shared_dict" directive is not allowed here - 名称只能含字母、数字、下划线,大小写敏感(
cache_v1和Cache_V1是两个独立字典) - 大小单位仅支持小写
k或m(如10m合法,10M或10mb会导致启动失败) - 最小分配值为 12KB;低于 8KB 直接触发 emerg 错误
- 同名字典不可重复定义,多个
include文件中要检查命名冲突
合理预估并分配内存大小
大小不是越大越好,需兼顾缓存命中率与系统开销:
- 过小:频繁触发 LRU 淘汰,有效数据被误清,缓存命中率骤降
- 过大:占用过多驻留内存,高并发下易引发系统压力
- 单 key 最长 255 字节;长标识(如带 UA 的 IP)建议先哈希压缩,例如
md5(ip .. ua) - 估算公式:预期 key 数 ×(平均 key_len + value_len + 内存开销),再上浮 20%~30% 作余量
在 Lua 中用原子操作安全访问
所有 API 都是原子的,但调用方式决定是否真正线程安全:
- 计数类场景(如限流)必须用
dict:incr(key, step, exptime):首次访问自动初始化为 0,避免get + set引发竞态 - 缓存结构化数据用
dict:set(key, val, exptime),单位为秒;value 最大支持 8MB,但建议控制在几 KB 内减少碎片 - 读取后需条件更新时,用
dict:get_set(key, new_val, exptime),它返回旧值并原子替换 - 禁用以下模式:
val = dict:get(k); if not val then dict:set(k, v, 60) end——两个请求可能同时判空并写入,导致覆盖或重复初始化
理解它的能力边界
快,但不万能,用前必须清楚限制:
- 数据随 Nginx
reload保留,但随进程退出**完全丢失**,不持久 - 仅限本机所有 worker 共享,**不跨机器**,无法替代 Redis 做集群同步
- value 不支持函数、闭包、含循环引用的 table
- 过期是惰性清理(访问时才检查),可主动调用
dict:flush_expired(n)批量清理(最多清 n 个)


















