504错误主因是least_conn仅按活跃连接数分配请求,未感知后端真实处理能力,导致流量持续打向响应迟缓节点;需结合健康检查、后端状态监控与连接日志定位根因。

当 Nginx 使用 least_conn 负载均衡策略时出现 504 Gateway Timeout,通常不是 least_conn 本身导致超时,而是后端节点响应慢、连接堆积或健康检查未及时剔除异常节点,导致请求被转发到已无响应能力的上游服务器。排查需聚焦在“连接分配逻辑”与“真实后端状态”的匹配性上。
确认 least_conn 是否真的把请求分给了最空闲节点
least_conn 是按当前活跃连接数(即已建立但尚未关闭的连接)选择上游,不考虑响应时间、队列长度或后端处理能力。如果某个后端因线程阻塞、数据库锁、GC 停顿等原因无法及时处理新请求,它的活跃连接数仍可能很低(比如只维持长连接但不读写),Nginx 就会持续往它转发请求,最终触发 proxy_read_timeout 或 upstream timeout,返回 504。
- 用
nginx -T检查 upstream 配置是否启用了least_conn,并确认没有被ip_hash或hash $request_uri等覆盖 - 开启 Nginx 连接日志:在 upstream 块中加
log_format upstream_log 'upstream=$upstream_addr, status=$upstream_status, time=$upstream_response_time';,配合access_log /var/log/nginx/upstream.log upstream_log; - 观察日志中 504 对应的
$upstream_addr是否集中出现在某一个后端 IP —— 若是,说明该节点虽连接数少,但实际已不可用
检查后端真实连接状态和处理能力
不能只看 Nginx 统计的“活跃连接数”,要验证后端进程是否真能接收并响应新请求。
- 登录对应后端服务器,运行
ss -tn state established '( sport = :8080 )' | wc -l(替换为实际端口),对比 Nginx 的upstream_keepalive和连接复用情况 - 用
curl -v http://backend-ip:port/health手动测试响应延迟;若健康接口也超时或耗时 >3s,基本可判定后端自身问题 - 检查后端应用的线程池使用率、CPU 负载、堆内存占用(如 Java 应用的
jstat -gc)、慢 SQL 或外部依赖(Redis、DB)超时日志
验证健康检查是否生效且配置合理
least_conn 不自带故障感知,必须依赖 health_check 或 max_fails/fail_timeout 主动剔除异常节点。若健康检查间隔太长、失败阈值过高,或检查路径返回假阳性,就会让“看似空闲实则瘫痪”的节点继续收流量。
- 确保 upstream 中配置了有效健康检查,例如:
health_check interval=5 fails=2 passes=2 uri=/health;
注意uri必须返回 200 且响应体轻量,避免引入额外延迟 - 检查
max_fails=2 fail_timeout=10s是否与业务 RT 匹配;若后端平均响应 800ms,但fail_timeout只设 3s,可能刚恢复就被反复踢入踢出 - 用
curl -I http://nginx-ip/upstream_conf?upstream=my_backend(需启用upstream_conf模块)查看各节点当前状态:是否显示down或unhealthy
临时缓解与长期优化建议
504 频发时先止损,再定位根因。
- 紧急:在 upstream 中对问题节点临时加
down标记,或用weight=0快速隔离 - 短期:将
least_conn改为round_robin+ 合理健康检查,观察是否仍有集中超时 —— 若消失,说明原问题是单点后端性能瓶颈而非负载策略缺陷 - 长期:在后端增加熔断(如 Hystrix/Sentinel)、限流(如令牌桶)、更细粒度的健康探针(如检查 DB 连接池可用数),并监控
upstream_response_time的 P95/P99 分位











