Nginx轮询在高并发下存在短时偏斜,因各worker独立维护计数器;验证需先串行确认循环顺序,再用ab压测统计分布,结合日志与响应头比对,并排除健康检查、keepalive、worker数及后端延迟等干扰。

轮询在高并发下不存在绝对均等,这是 Nginx 架构决定的——每个 worker 进程独立维护自己的轮询计数器,多请求同时到达不同 worker 时,会各自按序分发,导致短时分布偏斜。测试目标不是追求“完全相等”,而是确认整体符合轮转规律、长期统计趋近理论比例。
用串行请求验证轮转逻辑是否生效
排除并发干扰,先确认基础轮询机制正常工作:
- 在 upstream 中确保只配置 server 行,不带 weight、max_fails 或 ip_hash 等干扰项
- 在 location 块中添加:proxy_set_header X-Upstream-Addr $upstream_addr;
- 执行 10–20 次串行 curl(避免 & 并发):
for i in {1..15}; do curl -I http://your-domain/health 2>/dev/null | grep X-Upstream-Addr; sleep 0.1; done - 观察输出是否呈现可预期的循环顺序,如 A→B→C→A→B→C…,而非长时间卡在某一台
用 ab 工具做可控并发压测并统计分布
模拟真实压力,但控制变量以聚焦轮询行为:
- 使用
ab -c 10 -n 1000(10 并发 × 1000 总请求数),比单连接更贴近实际,又不至于掩盖轮询趋势 - 后端需返回唯一标识,例如响应头
X-Server-ID: node-a,便于归因 - 压测后提取全部响应头:
ab -c 10 -n 1000 http://your-domain/health 2>/dev/null | grep "X-Server-ID" | awk '{print $2}' | sort | uniq -c | sort -n - 三节点理想分布为 ≈333 / 333 / 334;若某节点低于 300 或高于 370,需检查 health_check 是否误剔除、或 upstream 中有隐式 weight
查 Nginx 访问日志确认真实转发路径
绕过客户端缓存和连接复用,以服务端记录为准:
- 修改 log_format,加入
$upstream_addr $upstream_status字段 - 重启 Nginx 后执行压测,再运行:
tail -n 1000 /var/log/nginx/access.log | awk '{print $12}' | sort | uniq -c(假设 $upstream_addr 是第 12 列) - 对比日志统计与响应头统计是否一致;若日志显示均衡但响应头不均,可能是后端自身重定向或 header 覆盖所致
- 注意:日志中出现
-表示未转发(如 503 或 timeout),这类请求不参与轮询计数,需单独排查失败原因
识别并排除常见干扰因素
很多“不均”其实与轮询算法无关,而是配置或环境导致:
- 健康检查干扰:临时网络抖动触发 max_fails,某节点被摘除数秒——压测前先 curl 所有后端 health 接口,确保全通;或临时注释 health_check 相关参数
-
keepalive 连接池影响:客户端复用连接会导致后续请求持续打到同一台——压测时在 upstream 中加
keepalive 0,或用 ab 的-k参数关闭 keepalive - worker 数量失配:若只启 1 个 worker,轮询计数器唯一,分布最稳定;但生产环境通常多 worker,此时应关注 1000+ 请求的总体比例,而非每 10 次是否严格交替
- 后端响应延迟差异大:某台处理慢,可能在压测窗口内完成请求数明显少——这不是轮询问题,而是后端性能问题,需结合 $upstream_response_time 日志字段分析











