加权轮询在高并发下“看似失效”主因是权重被会话保持、连接复用或健康检查掩盖;需检查upstream中是否含ip_hash/hash、keepalive设置及max_fails触发节点摘除。

加权轮询在高并发下“看似失效”,通常不是算法崩了,而是权重逻辑被其他机制覆盖、掩盖或干扰。重点不是重看配置语法,而是验证真实分发路径是否还受 weight 控制。
确认权重是否还在参与调度
高并发场景下,最容易让 weight “隐身”的是会话保持类指令。只要 upstream 块里写了 ip_hash、hash $cookie_session_id 或 sticky cookie,Nginx 就会直接忽略所有 weight 设置,改用哈希路由——此时看到的流量倾斜是设计使然,不是故障。
检查方法:
- 运行 nginx -T | grep -A10 "upstream backend"(把 backend 换成你实际的名字),确认块内没有 ip_hash 或 hash 指令
- 检查 location 块中是否误启了第三方 sticky 模块(如 nginx-sticky-module-ng),它的优先级高于 weight
- 如果用了 proxy_pass http://backend/,但 upstream 名拼错(比如写成 backends),Nginx 会当作域名解析,失败后 fallback 到第一个 server,等效单点
排除连接复用导致的假性倾斜
短连接下 weight 分布清晰,但高并发常伴随长连接(keepalive)。客户端复用 TCP 连接后,Nginx 默认将同连接后续请求持续打到同一个后端——这会让 access log 看起来像“某台机器吃下全部流量”,其实只是连接没刷新。
验证与缓解:
- 临时关闭 keepalive:在 upstream 块中加 keepalive 0,并确保 client 端也禁用连接复用(如 curl -H "Connection: close")
- 用 ab/wrk 发起纯短连接压测:ab -n 2000 -c 200 -H "Connection: close" http://your-domain/,再统计 $upstream_addr 首次分发结果
- 观察 stub_status 中各 server 的 requests 计数比,它统计的是实际处理请求数,不受连接复用干扰
检查健康检查是否悄悄摘除了节点
weight 再大,节点进不了轮询队列也没用。max_fails/fail_timeout 在高并发下更容易触发:某台机器响应稍慢、偶发超时,就会被标记为不可用,在 fail_timeout 期间彻底退出调度,剩余流量全压到活着的节点上,造成“权重失衡”假象。
排查动作:
- 查 error.log 中是否有大量 "upstream timed out" 或 "no live upstreams",定位哪台被踢出
- 确认所有 server 行的健康检查参数是否一致(不能有的写 max_fails=2,有的完全不写)
- 临时注释掉所有 max_fails 和 fail_timeout,用短连接压测,看流量分布是否回归权重比例
验证后端响应行为是否破坏了轮询节奏
加权轮询是确定性算法,但依赖后端及时、规范地响应。若某台机器响应头过大(如含超长 JWT)、返回非法状态行、或响应体中途断连,Nginx 可能直接关闭连接并重试下一个节点——日志里记的是“最终成功地址”,而非首次目标,导致统计失真。
建议做法:
- 对每台后端单独 curl -v /health,对比响应头大小(grep '^),差异超过 2KB 就需警惕
- 在 location 中加 proxy_next_upstream off(仅测试用),禁用自动重试,强制记录首次转发目标
- 用自定义 header 标识首转:后端返回 X-First-Upstream: A,客户端不透传该头,避免污染;再通过 log_format 记录它
不复杂但容易忽略











