Nginx 502 与 504 排查:从错误日志措辞定位到配置
Nginx 报 502 和 504,方向完全不同。502 是 Nginx 连上了上游却拿不到合法响应,504 是等上游响应等到超时。把这两类混在一起查,通常会在同一个配置项上反复改却不见效。下面按「先分类、再定位、最后改配置」的顺序说清楚。
一、先看错误日志里的具体措辞
tail -n 200 /var/log/nginx/error.log
502 常见的三种措辞,指向的原因不同:
connect() failed (111: Connection refused) while connecting to upstream—— 上游端口没有进程在监听。后端挂了、只监听了 127.0.0.1、或者容器重建后 IP 变了。upstream prematurely closed connection while reading response header from upstream—— 连接建立成功,但上游在写完响应头之前就关闭了连接。多是后端进程崩溃、OOM 被杀、或者应用自身超时先返回了空连接。no live upstreams while connecting to upstream—— 负载均衡组里所有节点都被健康检查判定为不可用,问题在健康检查配置而不是业务代码。
504 只有一类措辞:
upstream timed out (110: Connection timed out) while reading response header from upstream
看到这一句,直接说明请求已经发出,上游在 proxy_read_timeout 内没有返回第一个字节。
二、确认请求到底有没有到后端
这一步能立刻把问题范围砍掉一半。在上游机器上看连接和日志:
ss -lntp | grep ':8080'
ss -tn state established '( sport = :8080 )' | head
如果 ss 里能看到来自 Nginx 的 established 连接,但后端应用日志里没有任何对应请求记录,说明请求卡在了应用前面的一层——比如容器网络的 iptables 规则、Service 的端点没更新、或者应用线程池耗尽导致连接被 accept 后一直不处理。
如果连接都建不起来,是网络层或监听地址的问题,跟 Nginx 的超时配置无关。
三、几个最容易配错的地方
1. 超时预算不匹配
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_read_timeout 是两次读操作之间的间隔上限,不是整个请求的总时长。上游如果每 50 秒吐一个字节,60 秒的配置永远不会触发。反过来,上游做批量导出这类长任务时,把 proxy_read_timeout 调到 300s 只是把 504 往后推,真正该做的是把长任务改成异步任务加轮询。
2. upstream 用了域名却只在启动时解析
upstream backend {
server api.internal:8080; # 只在 reload 时解析一次
}
后端是容器或弹性伸缩时,IP 变了 Nginx 不知道,会持续往旧 IP 发请求,表现就是间歇性 502。改用变量加 resolver 可以强制每次解析:
resolver 10.0.0.2 valid=10s;
set $backend "api.internal:8080";
proxy_pass http://$backend;
注意用了变量之后,upstream 块里的 keepalive、权重这些就不生效了,需要自己在 proxy_http_version 1.1 和 proxy_set_header Connection "" 上补回来。
3. keepalive 没配,端口被 TIME_WAIT 占满
upstream backend {
server 10.0.1.10:8080;
keepalive 64;
}
keepalive 要生效,必须同时设置 proxy_http_version 1.1 并清掉 Connection 头,否则 Nginx 仍然每个请求新建连接。高 QPS 下这会迅速堆出大量 TIME_WAIT,ss -s 里 timewait 数量飙升的同时 502 开始出现,就是这个原因。
4. 缓冲区太小导致上游被提前中断
proxy_buffer_size 16k;
proxy_buffers 8 8k;
proxy_busy_buffers_size 16k;
上游响应头超过 proxy_buffer_size 时,Nginx 会把响应落到临时文件;如果 proxy_max_temp_file_size 为 0 且缓冲区不够,连接会被中断,日志里同样是 prematurely closed connection。响应头特别大的场景(大量 Set-Cookie)值得先怀疑这里。
四、worker 连接数不够也会报 502
grep -i 'worker_connections' /etc/nginx/nginx.conf
grep -c '^worker_processes' /etc/nginx/nginx.conf
worker_connections 是单个 worker 能同时处理的连接数,一个客户端连接会占用两个(前端 + 上游)。日志里出现 worker_connections are not enough 时,调大这个值比调超时有用得多。同时确认 ulimit -n 不低于这个配置,否则改了也不生效。
五、验证顺序
改完配置不要只看接口返回,按这三步确认:
nginx -t # 语法
nginx -s reload # 平滑生效
curl -o /dev/null -s -w '%{http_code} %{time_total}\n' https://example.com/api/health
time_total 接近配置的超时值,说明上游确实慢,属于容量问题而不是配置问题;time_total 很短但仍是 502,说明连接阶段就失败了,回头查监听地址和健康检查。
最后一点:502/504 在网关层看是同一个现象,在日志里是完全不同的原因。先按错误措辞分类,再逐层确认连接是否建立、请求是否到达应用,比反复调整超时参数有效。
- 点赞
- 收藏
- 关注作者
评论(0)