“upstream timed out”需结合日志字段定位根因:看$upstream_connect_time与$upstream_header_time分离程度判断网络或后端瓶颈,查$upstream_status序列识别重试模式,验证keepalive、超时参数是否匹配。

“upstream timed out”本身不指明原因,必须结合日志字段和上下文才能判断是网络抖动还是业务逻辑卡死。关键看超时发生在哪一阶段、各耗时指标是否同步异常、以及重试行为是否生效。
看 $upstream_connect_time 和 $upstream_header_time 的分离程度
这两个变量能快速定位瓶颈环节:
- 若 $upstream_connect_time 明显偏高(>1s)且波动剧烈,但 $upstream_header_time 正常(,说明连接建立慢、后续处理快——大概率是网络层问题:跨机房延迟、中间设备丢包、DNS 解析慢或防火墙策略抖动;
- 若 $upstream_connect_time 很低(,但 $upstream_header_time 超长(>2s),说明连接建立快,但后端迟迟不返回响应头——基本锁定为业务阻塞:慢 SQL、同步调用第三方接口超时、线程池打满、数据库锁等待或 JVM Full GC;
- 若两者都持续升高且变化趋势高度一致,需立即检查后端整体资源水位:CPU 持续 >90%、内存 OOMKilled、线程数达到上限、或连接池已耗尽。
查 $upstream_status 序列识别重试模式
这个字段记录每次 upstream 尝试的真实状态码序列(如 “504,502,200”),比单一 504 更有诊断价值:
- 如果大量请求的 $upstream_status 是空值或仅单个 200,但 error.log 里仍报 sporadic “upstream timed out”,说明超时只发生在首次请求、未触发重试——倾向偶发网络故障(如 SYN 重传失败、SYN flood 防御触发);
- 如果高频出现 逗号分隔的失败码(如 “504,504,200” 或 “502,504,200”),说明 proxy_next_upstream 已启用并反复兜底——这是后端不稳的典型信号:要么某台实例局部过载(如某个 Pod CPU 100%),要么网络抖动导致部分连接被重置;
- 若 $upstream_status 中频繁出现 “502” + “504” 组合,要重点排查后端是否主动关闭了 nginx 认为“可用”的空闲连接(比如 Spring Boot 默认 60s idle timeout 与 nginx keepalive 不匹配)。
验证连接池与超时参数是否对齐
很多“超时”其实不是后端慢,而是 nginx 自身连接管理失效:
- 检查 upstream 块是否配置 keepalive 32(建议 16–256),并确认配套设置了 proxy_http_version 1.1 和 proxy_set_header Connection '';
- 确认 proxy_connect_timeout ≤ 5s(非默认 60s),避免建连慢掩盖真实问题;
- 确保 proxy_read_timeout(读响应头) ,防止客户端已断开而 nginx 还在等后端;
- PHP-FPM 场景下,必须同步校准:fastcgi_connect_timeout、fastcgi_read_timeout 与 PHP 的 request_terminate_timeout 和 pm.max_children,否则会出现 accept 队列溢出或子进程重启期间的假超时。
排除中间链路干扰
即使后端响应快,以下因素也会引发 “upstream timed out”:
- 防火墙或安全组对长连接的空闲探测包(keepalive packet)误判并中断连接;
- 云厂商 SLB/NAT 网关设置的连接空闲超时(如阿里云 SLB 默认 900s)短于 nginx keepalive,导致连接被中间设备静默回收;
- 后端服务启用了 connection: close 头但未正确处理复用连接,nginx 下次复用时收到 RST;
- 内核 net.ipv4.ip_local_port_range 设置过小,在高并发下端口耗尽,新建连接卡在 SYN_SENT 状态。











