least_conn在长连接场景下“看似启用却没效果”,主因是活跃连接数统计失真或配套机制缺失;需验证nginx与后端连接数一致性、keepalive配置、健康检查及max_conns协同,排除版本与语法错误。

least_conn 在长连接场景下“看似启用却没效果”,通常不是算法本身坏了,而是它看到的连接数失真,或周边机制没跟上。排查重点不在 least_conn 指令是否写了,而在它依赖的“数据源”和“保护层”是否到位。
检查活跃连接数是否真实反映后端压力
least_conn 调度只看一个数字:当前每个 upstream server 的活跃 TCP 连接总数(含 keepalive 空闲连接)。如果这个数不准,算法就失去意义。
- 用 stub_status 查看 Nginx 统计值:访问
/nginx_status,确认各 server 的Active connections是否有明显差异;若长期全为 0 或全部接近 max_conns,说明连接未复用或已打满 - 在后端机器上交叉验证:运行
ss -tn state established '( dport = :8080 )' | wc -l,对比 Nginx 显示的数值。若 Nginx 显示 50,后端实际只有 5 条 ESTAB,说明 keepalive 未生效或连接被快速关闭 - 检查 upstream 中是否配置了 keepalive(如
keepalive 32;),且值不过大(>64 容易虚高账面连接数) - 确认 proxy_pass 所在 location 中设置了:
proxy_http_version 1.1;proxy_set_header Connection '';—— 缺一不可,否则后端可能主动断连
确认后端是否真正维持长连接
如果后端每请求都新建连接、立刻关闭,Nginx 统计的活跃连接数永远趋近于 0,least_conn 就退化为随机分配。
- 抓包验证:用
tcpdump -i any port 8080观察是否有大量SYN → ACK → FIN短周期连接,而非复用同一连接发多个 request - 检查后端配置:
Tomcat 需设maxKeepAliveRequests > 0和keepAliveTimeout > 5;
Spring Boot 加server.tomcat.max-keep-alive-requests=1000;
FastAPI/Uvicorn 启动加--keep-alive 5 - 检查响应头:后端返回中是否含
Connection: close?常见于错误响应、调试模式开启、WAF 插入或鉴权失败,这会强制关闭复用
验证健康检查与 max_conns 是否协同生效
least_conn 不识别“卡死但 TCP 未断”的节点。若某台后端正卡在 GC 或锁竞争,连接数低但无法响应,least_conn 仍会持续派请求过去——这不是失效,是缺少防护。
- 检查是否配置了 被动健康检查:
server 10.0.1.10:8080 max_fails=2 fail_timeout=15s;
并配合 location 中的proxy_next_upstream error timeout http_500 http_502; - 更推荐启用 主动健康检查(需 OpenResty 或 nginx_upstream_check_module):
check interval=3 rise=2 fall=3 timeout=1 type=http match=ok;
并定义match ok { status 200; body_pattern "OK"; },避免 HTTP 200 但业务已僵死 - 检查是否为每个 server 设置了 max_conns:
例如server 10.0.1.10:8080 max_conns=800;,一旦达到该值,Nginx 会跳过该节点参与 least_conn 比较,这是防止隐性过载的关键闸门
排除配置与版本硬性限制
一些基础错误会导致 least_conn 根本不加载或被静默忽略。
- 确认 least_conn 写在 upstream 块第一行,且未与其他负载策略(如 ip_hash、hash、least_time)混用
- 确认 Nginx 版本 ≥ 1.3.1(该算法自该版本正式支持);执行
nginx -v验证 - weight 参数在 least_conn 上无效,不要写
server ... weight=2;,改用max_conns表达容量差异 - 检查语法:运行
nginx -t,确保无 “directive is not allowed here” 类报错











