least_conn统计失真源于nginx活跃连接数与后端真实established连接不一致;需通过stub_status与ss命令比对、分析日志及tcpdump定位泄漏环节,并配平proxy_read_timeout、后端keepalivetimeout及max_conns实现修复。

排查 least_conn 统计失真,核心是确认 Nginx 看到的“活跃连接数”是否真实反映后端实际负载。连接未及时释放会导致连接数虚高、调度失效——新请求被错误导向看似空闲实则卡死的节点。
查 upstream 实时连接数是否可信
least_conn 的决策完全依赖 upstream server 的活跃连接数,这个值必须准确。先验证它是否被污染:
- 开启
stub_status,访问/nginx_status,重点看Active connections下各 backend 的数值变化趋势 - 用
ss -tn state established '( dport = :8080 )' | wc -l在后端机器上手动统计真实 ESTABLISHED 连接,与 stub_status 显示值比对:若 Nginx 显示 15,后端只有 3,说明有大量连接未释放(泄漏) - 检查 Nginx 日志中
$upstream_addr和$upstream_connect_time,若某节点连接建立耗时极短(如 0.001s)但后续无响应,大概率是空闲连接被复用后卡住未关
定位泄漏发生在哪一环
连接泄漏不是 Nginx 单方面问题,而是客户端、Nginx、后端三方生命周期错位的结果:
-
后端未正确关闭连接:检查后端服务是否禁用了 keep-alive timeout(如 Tomcat 的
connectionTimeout设为 -1 或过大),或未处理 FIN 包就直接 exit -
Nginx keepalive 池未回收空闲连接:确认 upstream 中
keepalive 32已配置,且 location 中有proxy_http_version 1.1和proxy_set_header Connection '';若后端返回Connection: close,Nginx 会拒绝复用,但不会主动清理旧连接 -
客户端异常断连:用
tcpdump抓包看是否有 RST 包,但 Nginx 未及时感知,导致连接状态滞留在“active”列表中(需结合proxy_next_upstream error timeout触发重试并清理)
用压测+观测组合验证泄漏点
静态配置检查不够,要通过可控压力暴露问题:
- 用 wrk 启动长连接压测:
wrk -c 100 -t 4 -d 60s --timeout 30s http://gateway/longpoll,确保每个连接保持到后端 sleep 返回 - 压测中每 2 秒执行一次:
curl http://localhost/nginx_status 2>/dev/null | grep Active+ss -tn state established '( dport = :8080 )' | wc -l,记录双曲线走势 - 压测结束后等待 60 秒,再查两端连接数:若 stub_status 仍显示高位而后端已归零,说明 Nginx keepalive 池未释放空闲连接——常见于
proxy_read_timeout远大于后端心跳间隔
关键修复动作
不靠猜,靠配平三方超时和行为:
- 设
proxy_read_timeout为后端最长空闲响应时间的 1.5 倍(例如后端 ping/pong 30 秒一次,就设 45–60 秒) - 后端服务显式设置
keepAliveTimeout,且该值必须 大于 Nginx 的proxy_read_timeout,避免后端先断 - 在 upstream server 行中加
max_conns=xxx,一旦达到即跳过调度,防止单节点因泄漏持续吸流 - 启用
proxy_next_upstream error timeout http_502,让失败连接触发自动重试和连接清理











