现象
客户端收到 504;错误日志出现 upstream timed out (110: Connection timed out) while reading response header from upstream;健康检查正常但慢接口失败;后端稍后打印了请求日志,而客户端早已收到 504。
诊断
先读错误日志,确认超时发生在连接、发送还是读取阶段:
tail -n 200 /var/log/nginx/error.log | grep -E 'upstream timed out|no live upstreams|connect\(\) failed'
nginx -T 2>/dev/null | grep -nE 'proxy_(read|connect|send)_timeout|proxy_next_upstream'
while reading response header 指向应用响应慢,while connecting 指向不可达或 accept 队列满。默认 proxy_read_timeout 是 60 秒,注意匹配 location 的实际覆盖值。再绕过 nginx 直连后端测 TTFB:
curl -o /dev/null -s -w 'connect=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total}' http://127.0.0.1:3000/slow-endpoint
TTFB 超过超时值即可确认是后端问题;直连很快则查 nginx 配置、DNS 与网络。用 ss -ltnp | grep ':3000' 和 established 连接数判断后端是否饱和。
根因
nginx 在 proxy_read_timeout 内没有收到上游响应头,于是返回 504 并关闭客户端连接。上游请求可能仍在执行,也可能在客户端放弃之后才完成。
修复
先修慢处理或外部依赖,再按 location 设置合理预算,并开启 upstream keepalive:
upstream app_backend {
server 127.0.0.1:3000;
keepalive 32;
}
location /reports/ {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 2s;
proxy_read_timeout 120s; # 仅用于确实需要长预算的接口
proxy_next_upstream error timeout;
proxy_pass http://app_backend;
}
proxy_next_upstream 只适合幂等请求,POST 重试可能重复写入。真正耗时的导出应改为后台任务加状态查询,避免长期占用 worker 连接。
验证
重放原请求应在预算内返回 200,错误日志不再新增 upstream timed out;压测下 TTFB P95 低于 proxy_read_timeout,到上游的 established 连接数有界。