worker_processes数量直接影响shared dict的锁竞争与内存效率,需权衡并发能力与slab锁争用;推荐auto配合cpu_affinity,避免超核数配置,并协同multi_accept、key分片等策略优化。

worker_processes 设置直接影响 shared dict 的锁竞争强度和内存访问效率,不能只看 CPU 核数拍脑袋定值。关键在于让每个 worker 有足够并发能力,又不因进程过多加剧 slab 锁争用或上下文切换开销。
worker_processes 数量与 shared dict 竞争的关系
shared dict 底层使用 Nginx slab 分配器,所有读写都需加锁保护哈希桶。当 worker 进程数过多、而业务又集中更新少数 key(如全局计数器、热点配置)时,多个 worker 可能频繁争抢同一 slab slot,导致 P99 延迟毛刺。
- worker_processes = 1:无跨进程竞争,但无法利用多核,吞吐受限,仅适合调试或极低流量场景
- worker_processes = auto(即 CPU 核数):常规推荐起点,但需配合 worker_cpu_affinity 避免进程在核心间漂移
- worker_processes > CPU 核数:通常有害——增加调度开销,且不会提升 shared dict 吞吐;反而可能因更多 worker 同时尝试 set 同一 key 加剧锁等待
结合 shared dict 使用的合理配置组合
不是孤立调 worker_processes,而是与事件模型、连接分配、共享字典使用方式协同优化:
- 保持 worker_processes auto,同时启用 worker_cpu_affinity auto,确保每个 worker 绑定独立 CPU 核心
- events 块中设 multi_accept on 和 worker_connections 16384,让单个 worker 充分承载连接,减少 worker 间请求分发频次,间接降低对同一 shared dict key 的并发冲击
- shared dict zone 大小要预留余量:例如声明 lua_shared_dict my_cache 128m,但实际活跃 key 占用建议控制在 60–70% 容量内(通过 my_cache:info() 检查 items / capacity 比值),避免因假性满载触发频繁 slab 分配失败
高并发下缓解 shared dict 锁瓶颈的配套策略
即使 worker_processes 配置合理,若业务逻辑本身存在高频单 key 写,仍会卡在 slab 层。必须从 Lua 层设计入手:
- 拆 key:把 counter:global 改成 counter:global:shard_0 到 counter:global:shard_7,写入时按 hash 分散,显著降低单 slot 竞争
- 写操作异步化:非实时强一致场景,用 ngx.timer.at 延后 set,或改由 Redis + Lua 原子指令完成计数,shared dict 仅作本地缓存
- 读多写少场景启用 get_stale:允许读已过期数据,跳过锁等待,再由后台协程异步刷新,适用于配置类、降级兜底类缓存
C 模块访问 shared dict 的特别约束
若 C 模块需读取 shared dict(如自定义限流模块),必须严格遵守生命周期规则,否则会放大竞争风险或引发段错误:
- C 层只能读,禁止任何 write 操作——OpenResty 不保证 C 层写入的线程安全
- 每次访问前必须调用 ngx_http_lua_find_zone 获取有效 zone 指针,不可缓存或硬编码
- 仅限 worker 进程上下文调用,master 进程中调用无效且危险










