Nginx 502/504 排障:先按 error.log 关键字分流,别急着重启
502 和 504 都表示 Nginx 作为网关没有拿到上游的正常响应,但病因不同。502 多发生在连接上游或读取响应的早期,504 更常见于上游没在规定时间内完成。
每次重启 Nginx 都是打地鼠:打掉的是眼前表象,病根要么在配置里,要么在后端进程,要么在网络那一层。同样,先把 proxy_read_timeout 从 60 秒改成 600 秒,也只是让连接占用更久。
先看 error.log 的关键字
connect() failed (111: Connection refused) while connecting to upstream:Nginx 找到了目标地址,但目标端口没有接受连接。upstream timed out (110: Connection timed out) while connecting to upstream:建立上游连接就已超时,方向通常是地址、路由、防火墙或服务负载。upstream timed out ... while reading response header from upstream:连接已建立,但后端迟迟没返回响应头,更像应用慢、数据库卡住或超时时间不匹配。no live upstreams:配置中的上游没有可用节点,常见于 upstream 健康状态或服务发现问题。recv() failed (104: Connection reset by peer):上游主动断开连接。
分层判断
| 现象 | 判断方向 |
|---|---|
Connection refused | 目标主机可达,但端口没有服务监听。启动或修复后端,或改回正确端口。 |
Operation timed out | 不一定是进程退出,可能是容器网络、路由或防火墙问题。 |
| 返回 200、401 或应用自己的 500 | 上游至少能响应,继续检查 Nginx 的 proxy_pass、请求头、路径和超时。 |
| 本机访问正常,Nginx 访问失败 | 检查 Nginx 是否在容器、chroot 或其他网络命名空间中;127.0.0.1 指向的是 Nginx 自己所在的环境,不一定是宿主机。 |
| 本机访问 Nginx 502,直连 upstream 也失败 | 问题在 upstream。 |
| 本机访问 Nginx 504,直连 upstream 响应慢 | 问题在 upstream 处理时长。 |
| 本机访问 Nginx 慢,直连 upstream 正常 | 问题多半在 Nginx 配置、DNS、连接复用或内核连接队列。 |
配置层面的常见错
- 上游地址/端口没同步:发版后服务换了端口,Nginx 还在打老端口。
- 协议写错:上游只提供 HTTP,却写成
https://;或者上游要求 TLS,Nginx 却用明文连接。 - 路径拼接不符合预期:
proxy_pass http://backend;与proxy_pass http://backend/;在带 URI 的 location 下行为不同。
超时参数不要混为一谈
504 通常意味着请求已经进入代理流程,但上游没有及时完成。不要简单地把 proxy_read_timeout 从 60 秒改成 600 秒:如果真正原因是数据库锁、死循环或下游 API 卡死,你只是让连接占用更久,并把故障放大。
proxy_connect_timeout:控制建立连接的等待时间。proxy_send_timeout:针对向上游发送请求。proxy_read_timeout:针对两次读取上游响应之间的等待。
提高读取超时不会修复「端口没人监听」的 502,也不会解决应用本身崩溃。
location /api/ {
proxy_pass http://backend_smart;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 60s;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 15s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_intercept_errors on;
error_page 502 503 504 = @fallback;
}
location @fallback {
add_header Content-Type application/json;
return 503 '{"error":503,"message":"Please try again later"}';
}
upstream 健康检查与故障转移:
upstream app_servers {
server 10.0.0.2:9000 max_fails=3 fail_timeout=30s;
server 10.0.0.3:9000 max_fails=3 fail_timeout=30s;
}
max_fails 设置过小时,一次偶发断连就会让 Nginx 在 fail_timeout 时间内认为上游挂掉,持续返回 502。
HTTPS 两条链路
客户端到 Nginx,以及 Nginx 到 HTTPS 上游,是两条独立链路。客户端证书过期、域名不匹配时浏览器通常直接提示 TLS 错误;Nginx 连接 HTTPS 上游失败,会在 error log 中看到 SSL handshake、certificate verify 或协议错误,外观上可能被误认为 502。
确认这几点:证书未过期、SAN 包含访问域名、完整证书链已部署、proxy_ssl_server_name 与上游要求一致。不要为了绕过生产问题永久关闭证书验证。
日志字段要打全
没有 upstream_response_time、upstream_status,排 5xx 会很被动。access.log 里按状态码过滤 502/504,error.log 按关键字过滤:
grep -E "connect\(\) failed|upstream timed out|reset by peer|no live upstreams" /var/log/nginx/error.log | tail -100
真实案例:
- 案例一:502,error.log 显示
connect() failed (110: Connection timed out),telnet 测试一切正常,最后发现云 SLB 与后端之间的健康检查出问题,SLB 认为后端不健康,把流量都打到同一台机器上,那台机器扛不住超时。 - 案例二:发版后部分接口 502、部分正常,检查 upstream 地址没改,新服务在新端口,Nginx 还在打老端口。
- 案例三:504 根因是慢 SQL。
proxy_read_timeout15 秒,业务方第一反应改成 60 秒;直连 upstream 同样慢,数据库里有多条全表扫描慢 SQL。正确做法是优化 SQL 或限流,而不是拉长超时。