Nginx通过master进程创建shared memory zone供所有worker进程直接访问,实现高效跨进程状态共享;该机制支撑limit_req、limit_conn及lua_shared_dict等限速与计数功能,但需合理预估内存大小并注意reload清空等限制。

Nginx 本身不提供进程间共享内存的原生编程接口,但其通过 shared memory zones(共享内存区)机制,在 master 进程启动时分配一块跨 worker 进程可见的共享内存区域,供所有 worker 进程读写。这一机制是实现全局限速(如 limit_req)、连接数限制(limit_conn)、以及自定义计数逻辑(借助第三方模块或 Lua)的基础。
shared memory zone 是如何工作的
Nginx 的每个 shared memory zone 由 master 进程统一创建并映射到所有 worker 进程的地址空间中。worker 进程通过指针直接访问该内存块,无需系统调用或序列化开销,因此性能极高。zone 内部通常采用哈希表结构组织数据(例如按 IP、请求 URI 或自定义 key 索引),支持 O(1) 平均查找与更新。
- zone 在配置中通过
limit_req_zone、limit_conn_zone或lua_shared_dict显式声明,必须指定名称和大小 - 所有 worker 共享同一份 zone 数据,天然支持多进程下的状态一致性
- zone 中的数据生命周期与 Nginx 进程一致;reload 时 zone 会被清空(除非使用
nginx -s reload且配置未改动 zone 定义)
用 limit_req 实现基于 IP 的请求速率限制
这是最典型的共享内存应用。Nginx 使用 limit_req_zone 定义一个 zone,再用 limit_req 指令在 location 中启用:
-
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s;:以客户端二进制 IP 为 key,开辟 10MB zone,限制平均速率 5 请求/秒(支持漏桶算法) -
limit_req zone=ip_limit burst=10 nodelay;:允许最多 10 个请求排队,超出立即拒绝(nodelay避免延迟响应) - 所有 worker 进程共用
ip_limitzone,对同一 IP 的请求无论落到哪个 worker,都能被准确计数和限速
用 lua_shared_dict + Lua 实现灵活计数逻辑
官方模块能力有限,但通过 ngx_lua 模块的 lua_shared_dict,可在 Lua 层安全地操作共享内存:
- 在 http 块中定义:
lua_shared_dict counter_dict 5m; - 在 access_by_lua_block 中读写:
local dict = ngx.shared.counter_dict; dict:incr("api_v1_count", 1) - 支持原子增减(
incr)、设置过期(set(key, val, exptime))、条件更新等,适合实现日粒度计数、用户配额、频次统计等场景 - 注意:Lua 字典操作是线程安全的,但需避免在单次请求中多次
incr同一 key 导致精度漂移(建议一次计算后单次写入)
注意事项与常见陷阱
共享内存虽高效,但误用易引发问题:
- zone 大小需预估:key 数量 × (平均 key 长度 + value 大小 + 哈希表开销),不足会导致 “no memory” 错误或哈希冲突激增
- key 设计影响效果:用
$remote_addr不如$binary_remote_addr节省内存(后者固定 4/16 字节) - reload 会重置 zone;若需持久化计数,需配合外部存储(如 Redis)做定期同步或 fallback
- 非 master-worker 模型(如 Windows 下的多线程模式)不支持 shared memory zone,此时功能不可用










