高效状态共享依赖共享内存区与轻量同步机制,所有跨worker状态必须置于shared memory zone中,通过原子操作或分片自旋锁保障并发安全,ngx.ctx等请求上下文无法跨worker共享。

高效的状态共享在 Nginx 多进程架构中不靠“传递上下文”,而是靠“统一内存视图 + 轻量同步机制”。每个 worker 进程独立运行、互不通信,但能安全读写同一块物理内存里的状态数据——这才是真正 scalable 的设计。
共享内存是唯一可靠载体
所有跨 worker 的状态(限流计数、上游健康状态、SSL 会话、缓存元数据)都必须落在 shared memory zone 中。master 进程启动时用 mmap(MAP_SHARED) 分配这块内存,fork 后所有 worker 自动继承映射,虚拟地址可能不同,但底层物理页相同。Nginx 内部一律用偏移量寻址,避免指针失效问题。
- 配置必须显式声明:如
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s或upstream backend { zone backend_zone 64k; ... } - 大小需预估留余:过小触发 LRU 驱逐,过大浪费内存;reload 会清空 zone(除非配置未变且 reload 行为特殊)
- Windows 原生版不支持 zone,会降级为 per-worker 独立状态
读写安全靠原子操作优先
对简单整型字段(计数器、标志位、时间戳),Nginx 优先使用 ngx_atomic_t 类型和底层汇编原子指令(如 x86 的 LOCK XADD),全程用户态完成,无系统调用、无调度延迟。
- 适合场景:每秒数万次的请求计数、连接数累加、失败次数递增
- 不适用场景:需要多字段一致性更新(如“查余额→扣减→写日志”),此时必须退回到锁保护
- Lua 中通过
lua_shared_dict调用的incr()、set()底层即走原子路径
必要时才用自旋锁分片保护
当操作涉及结构体修改或链表增删(如 SSL session 插入哈希桶、upstream server 状态切换),就需要 ngx_shmtx_t 自旋锁。它不是系统 mutex,而是基于 CAS 的轻量锁,锁粒度按需分片:
- 限流模块按客户端哈希值分桶,每个 bucket 独立一把锁
- SSL 缓存将 session key 映射到固定 slot,只锁该 slot 内部链表
- 锁变量与热点数据严格 cache line 对齐(64 字节),防止伪共享
避免误用“上下文共享”的常见误区
很多人试图让不同请求或不同 worker 共享 ngx.ctx 或模块 ctx,这是根本行不通的。这些结构体生命周期绑定单个请求,分配在 request pool 中,worker 之间完全隔离。
-
/main中设ngx.ctx.a = 1,子请求/sub读不到;重定向后ngx.ctx重置为空 - 两个并发请求即使来自同一 IP,也由不同 worker 处理,各自有独立
ngx.ctx - 真正要共享的,从来不是“请求上下文”,而是“全局状态”——而它只存在于 shared memory zone 里











