nginx 多 worker 流量统计依赖共享内存 zone 实现全局聚合:各 worker 原子更新同一块共享内存中的计数器,查询接口读取并格式化该内存数据;需合理配置 zone 大小、稳定 key 及避免日志或局部变量替代。

Nginx 的 Worker Process 本身不直接做跨进程的“统计聚合”,而是通过共享内存(shared memory)机制协同完成。每个 worker 独立处理请求、更新本地计数,但所有 worker 共用同一块共享内存区域——这才是流量统计能“聚合”的关键。
Worker 进程间如何实现一致的流量统计
- 所有 worker 进程映射同一块共享内存(如
vhost_traffic_status_zone或reqstat zone),里面存放哈希表或 slab 分配的统计结构 - 每个请求到达时,对应 worker 在共享内存中定位 key(如
$server_name、$upstream_addr或自定义set_key),然后原子地增减计数器(使用 CAS 或锁保护) - 统计指标(请求数、响应字节数、响应时间总和等)都存于共享内存,天然支持多 worker 并发写入
- 查询接口(如
/status或/reqstat)由任一 worker 响应,读取并格式化整块共享内存中的聚合结果
⚠️ 注意:如果共享内存大小不足(比如
32m不够存几千个虚拟主机+上游节点的组合),会出现ngx_slab_alloc() failed: no memory错误,需调大(如64m或128m)
实际配置中影响聚合效果的关键点
-
必须声明 zone:
vhost_traffic_status_zone shared:vts:64m;或reqstat zone=reqstat:10M;是前提,没有它就只有单 worker 视角 -
key 要稳定且可复用:用
$server_name比$host更可靠;泛域名建议配合map归一化,避免 key 泛滥导致内存碎片 -
避免频繁创建新 key:例如用
$request_uri做 key 会因带参 URL 导致 key 数爆炸,宜用$host+$uri截断或白名单路径 -
时间类指标依赖采样逻辑:响应时间(
avg,max)不是实时计算,而是滚动窗口内累加/计数后除得,精度取决于共享内存结构设计
为什么不能靠日志或 access_phase 模块替代
- 日志是异步落盘,无法提供毫秒级聚合视图,也不支持
sum/avg/max等在线计算 - 单 worker 内的 C 模块(如
http handler)若只操作局部变量,统计结果仅限该 worker,无法体现集群真实负载 - 只有共享内存 + 原子操作 + 统一 zone,才能让 4 个 worker 同时写、任意一个 worker 读,输出全局一致的数字
不复杂但容易忽略











