Nginx长连接复用导致轮询偏移,本质是keepalive与轮询逻辑冲突;需通过$upstream_addr和$connection_requests日志验证复用行为,检查proxy_http_version、Connection头及后端keepalive兼容性,并结合least_conn、健康检查与stub_status综合调优。

轮询本身不感知连接状态,所谓“长连接失效导致分发偏移”,本质是连接复用机制与轮询逻辑冲突所致——Nginx 在启用 keepalive 后,会复用到同一后端的空闲连接;若某节点连接池未及时释放或复用策略未对齐,就会让后续请求持续打向该节点,打破轮询的均匀性。
确认是否真在复用连接而非轮询
先验证当前行为是轮询失效,还是连接复用正常但被误判为“偏移”:
- 在
log_format中加入$upstream_addr和$connection_requests,观察同一客户端 IP 的多次请求是否始终命中同一upstream_addr,且$connection_requests持续递增(如从 1→47) - 检查
upstream块中是否配置了keepalive 32类参数;若已启用,轮询本就不应“严格交替”,而是优先复用已有连接 - 临时关闭 keepalive(注释掉
keepalive行),再压测观察$upstream_addr是否恢复均匀轮转——若恢复,说明原问题确由复用引起
检查 keepalive 配置与后端兼容性
keepalive 复用依赖 Nginx 与后端双方对 HTTP/1.1 和 Connection 头的正确处理:
- 确保
location块中设置了proxy_http_version 1.1和proxy_set_header Connection "",否则后端可能主动关闭连接,导致复用失败 - 后端服务需支持长连接:例如 Spring Boot 默认启用 keepalive,但若设置了
server.connection-timeout=-1或反向代理中间件(如 Tomcat 的maxKeepAliveRequests)限制过严,会导致连接被提前断开 - 用
ss -tn state established | grep :端口在后端机器上查看实际 ESTABLISHED 连接数,对比各节点是否严重不均;若某节点连接数远高于其他,说明其连接未被有效回收或复用过度
识别并拦截异常复用节点
当某节点因连接堆积、响应慢或线程阻塞导致复用失衡时,需靠健康检查+连接数感知快速干预:
- 启用
least_conn替代纯轮询:它会在复用基础上,优先选择当前活跃连接数更少的节点,缓解单点堆积 - 调低
max_fails=2并缩短fail_timeout=15s,配合proxy_next_upstream error timeout http_503,让响应延迟高或频繁断连的节点更快被标记为 down - 在 error_log 中搜索
"upstream connection is busy"—— 这表示该节点的 keepalive 连接池已空,Nginx 被迫新建连接,此时 least_conn 失效,需检查后端连接池配置(如数据库连接池 maxActive、HTTP 客户端最大并发数)
验证真实分发效果
别只看日志分布,要结合连接态和业务指标交叉判断:
- 用
curl -sI http://nginx-ip/api/test多次请求,比对响应头中的X-Upstream(需后端注入)是否符合预期轮转节奏 - 开启
stub_status,访问/nginx_status查看Active connections和各 upstream 的State,确认是否有节点长期处于down或unavail - 模拟一个后端节点响应变慢(如加
sleep 2),观察其余节点是否承接更多流量;若未明显转移,说明健康检查未生效或proxy_next_upstream配置缺失


















