加权轮询因不感知长连接状态导致负载倾斜,应改用least_conn并调优keepalive参数,结合连接级观测与响应时间分析精准定位根因。

加权轮询(weighted round-robin)本身不感知连接状态,只按权重比例分发新请求;而长连接复用会让一个 TCP 连接承载大量后续请求——这些请求全部落到同一台后端,但调度器“看不见”它们。这就造成日志里请求数看似均衡,实际连接和真实负载严重倾斜。排查核心是跳出“看请求数”的惯性,转向连接级观测。
确认是否真为连接级偏差而非请求分布问题
轮询算法只管新连接的派发节奏,不管已有连接上跑了多少请求。若客户端(如 App、浏览器、gRPC SDK)复用 HTTP/1.1 或 HTTP/2 连接,偏差就必然发生。
- 查 Nginx access log 中 $upstream_addr 字段,统计 不同 backend 的 client:port 对数量(即独立 TCP 连接数),不是请求数。若长期只有 2–3 台 backend 出现在该字段,说明连接已固化
- 在后端服务器执行 ss -tnp | grep :your_port | grep ESTAB | awk '{print $5}' | sort | uniq -c | sort -nr,观察 ESTABLISHED 连接的真实 IP 分布
- 临时关闭长连接:在 location 中注释掉 proxy_http_version 1.1 和 proxy_set_header Connection '',观察连接分布是否立刻变均匀——若恢复均匀,基本可锁定是 keepalive 复用导致
改用 least_conn 替代加权轮询
least_conn 直接基于当前活跃连接数做决策,天然适配长连接场景,且支持加权(Nginx 1.15+)。
- 配置示例:upstream backend { least_conn; server 10.0.1.10:8080 weight=3; server 10.0.1.11:8080 weight=1; }
- 它不会强制绑定,也不受客户端 IP 或 URI 影响,每次新请求都流向连接最少的节点,动态平衡效果明显
- 避免混用 ip_hash 或 hash $request_uri,否则会加剧连接集中,抵消 least_conn 效果
收紧 upstream keepalive 参数
Nginx 自身的连接池管理不当,会放大偏差:池子太大、超时太长,空闲连接长期滞留某 backend,新请求仍被轮到它。
- 在 upstream 块中显式设置:keepalive 32;(建议值 16–64,根据并发量调整,不要盲目设上千)
- 后端服务同步调小 keepalive_timeout(如 Tomcat 的 keepAliveTimeout 设为 30–60s),避免僵死连接占位
- 确保系统 ulimit -n 足够支撑该连接池规模,否则 Nginx 启动失败或静默降级
补充验证:区分响应延迟与连接偏差
连接数少 ≠ 处理快。若某节点连接数低但 $upstream_response_time 持续偏高,可能是它卡住了长连接(如 GC、锁竞争、慢查询),导致连接无法释放,进而误导 least_conn。
- 在 log_format 中加入:$upstream_response_time $upstream_connect_time $upstream_header_time
- 重点比对各 backend 的 upstream_response_time 分布:若某台 consistently >500ms,优先排查其自身性能瓶颈,而非调度逻辑
- 必要时搭配 least_time header last_byte(需 nginx ≥ 1.19.1 + 模块),在连接数基础上叠加响应速度维度











