nginx worker进程通过master预分配的mmap共享内存实现数据共享,各worker以字节偏移寻址,依赖原子操作(如ngx_atomic_t)和轻量锁同步;共享内存仅存元数据(如缓存key、ssl会话),响应体另存;协同采用“写隔离+乐观更新”,非强一致。

Nginx 的 worker_processes 本身不共享内存或缓存——每个 worker 是独立进程,地址空间隔离。所谓“共享”,是靠 master 进程在启动时预分配一块物理内存(通过 mmap(MAP_SHARED | MAP_ANONYMOUS)),再由 fork 继承,使所有 worker 映射到同一块共享内存区域;数据同步则依赖原子操作与轻量锁,而非进程通信。
共享内存不是自动同步,而是统一映射 + 偏移寻址
master 进程启动时调用 ngx_shm_alloc() 分配匿名共享内存,大小由配置中的 zone 指令决定(如 limit_req_zone ... zone=ip_limit:10m)。fork 后各 worker 进程获得该内存的映射权限,但虚拟地址可能不同。Nginx 内部一律使用**字节偏移量**定位字段,避免指针失效。这块内存生命周期由 master 管理,worker 退出不释放,reload 时默认清空(除非 zone 配置未变)。
计数器靠原子类型,不依赖锁
高频更新的状态(如请求数、令牌桶余量、活跃连接数)必须用 ngx_atomic_t 类型,底层调用 CPU 原语(如 x86 的 LOCK XADD),全程用户态完成,无上下文切换:
-
limit_req中每个 IP 对应的令牌数,是ngx_atomic_uint_t字段,worker 直接原子增减; -
stub_status的nginx_stub_status_active等指标,各 worker 并发原子累加,不会丢值; - 切忌在 Lua 中对同一 key 多次调用
incr(),或在 C 模块中直接写counter++——前者因浮点精度截断导致统计偏低,后者非原子,必然竞争出错。
缓存只存元数据,响应体另存别处
Nginx 不把完整响应体塞进共享内存,而是仅存放控制信息:
-
proxy_cache或fastcgi_cache的 key 索引、过期时间、状态标记(valid/expired)等元数据放共享内存,减少磁盘查找; -
ssl_session_cache shared:SSL:50m存储会话 ID 与加密参数,复用时直接查共享区,跳过 TLS 握手; - 所有条目由 slab 分配器管理,插入/删除需短暂获取
ngx_shmtx_t自旋锁,临界区极短(仅操作红黑树节点或哈希桶)。
协同逻辑是“写隔离 + 乐观更新”,不是强一致
不同模块利用 zone 实现弱一致性,核心思路是降低争抢而非强制同步:
-
limit_req:每个 worker 先查本地滑动窗口,额度不足时才尝试原子扣减共享 zone 配额,失败即拒绝; -
lua_shared_dict:提供incr、set(key, val, exptime)等原子方法,适合日粒度计数或用户频控; - upstream 健康检查:启用
zone backend_zone 64k后,所有 worker 共享后端节点的 up/down 状态、失败次数、当前连接数,避免因状态隔离误发请求。











