如何用 Nginx lua_shared_dict 实现跨进程的高性能限流同步?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1106个文字,预计阅读时间需要5分钟。
直接说结论:
为什么 lua_shared_dict 适合限流而不是 Redis
因为它是 Nginx worker 进程直接 mmap 映射的同一块内存,没有序列化、没有网络 IO、没有上下文切换。一次 incr 调用平均耗时在 100ns 级别,而 Redis 单次 INCR 至少是毫秒级——尤其在每秒上万请求的网关场景,差两个数量级。
但它不是万能的:数据随 Nginx reload 清空;不支持复杂查询;value 不能存函数或循环 table;key 长度不能超过 255 字节。
- 适合场景:IP/Token/URI 粒度的计数、令牌桶、滑动窗口(需自己维护时间戳)
- 不适合场景:需要持久化、跨机器同步、模糊匹配或聚合统计
lua_shared_dict 必须放在 http 块里,且不能重复定义
这是最常踩的坑:有人把 lua_shared_dict rate_limit 5m; 写在 server 或 location 块里,Nginx 启动直接报错 nginx: [emerg] "lua_shared_dict" directive is not allowed here。
另一个隐性问题:同名字典只能定义一次。
本文共计1106个文字,预计阅读时间需要5分钟。
直接说结论:
为什么 lua_shared_dict 适合限流而不是 Redis
因为它是 Nginx worker 进程直接 mmap 映射的同一块内存,没有序列化、没有网络 IO、没有上下文切换。一次 incr 调用平均耗时在 100ns 级别,而 Redis 单次 INCR 至少是毫秒级——尤其在每秒上万请求的网关场景,差两个数量级。
但它不是万能的:数据随 Nginx reload 清空;不支持复杂查询;value 不能存函数或循环 table;key 长度不能超过 255 字节。
- 适合场景:IP/Token/URI 粒度的计数、令牌桶、滑动窗口(需自己维护时间戳)
- 不适合场景:需要持久化、跨机器同步、模糊匹配或聚合统计
lua_shared_dict 必须放在 http 块里,且不能重复定义
这是最常踩的坑:有人把 lua_shared_dict rate_limit 5m; 写在 server 或 location 块里,Nginx 启动直接报错 nginx: [emerg] "lua_shared_dict" directive is not allowed here。
另一个隐性问题:同名字典只能定义一次。

