服务覆盖:昆明·曲靖·玉溪·保山·昭通·丽江·普洱·临沧·楚雄·红河·文山·西双版纳·大理·德宏·怒江·迪庆

Nginx 502 Bad Gateway的7种死法和排查思路

eycit 2026-04-19 -3 次阅读 系统安装
---

theme: default themeName: "默认主题" title: "Nginx 502 Bad Gateway的7种死法和排查思路"


Nginx 502 Bad Gateway的7种死法和排查思路

线上服务突然502,这种事我见过太多次了。有的人一上来就重启Nginx,运气好可能管用5分钟,运气不好问题照样在。502不是Nginx的问题——它是Nginx告诉你:"我试过了,但后面的服务不行。"

这句话的意思是:Nginx作为反向代理,已经成功接收了客户端请求,但在把请求转发给上游服务(upstream)的时候出了问题。Nginx本身没挂,挂的是它后面的东西。

下面我把线上遇到过的7种502场景列出来,每种都配上具体现象、排查命令和解决方法。建议收藏,半夜出事了翻出来对照着查。

第一种:upstream超时

现象: 部分请求502,部分请求正常。被502的请求普遍耗时较长,后端服务本身是正常的。 原因: 后端处理请求的时间超过了Nginx配置的超时阈值,Nginx主动断开了连接并返回502。 排查:
# 查看Nginx错误日志,搜索upstream timed out
grep "upstream timed out" /var/log/nginx/error.logtail -20

日志里能看到类似这样的内容:

upstream timed out (110: Connection timed out) while reading response header from upstream
解决: 调大超时参数,但别无脑改到300秒。根据业务实际情况来:
location /api/ {

proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_buffering on; }

`proxy_connect_timeout`是连接upstream的超时时间,一般5秒足够。`proxy_read_timeout`是读取响应的超时时间,这个才是最常需要调的。如果你的API确实需要处理很长时间(比如导出大文件),那就调大。但如果正常请求不应该超过5秒还超时,那问题在后端,不是Nginx。

第二种:PHP-FPM进程耗尽

现象: 流量高峰期集中爆发502,低峰期完全正常。Nginx错误日志里有`Connection refused`或`no live upstreams`。 原因: PHP-FPM的`pm.max_children`设置太小,所有worker进程都在忙,新请求进不来。 排查:
# 查看PHP-FPM当前进程数
ps auxgrep php-fpmgrep -v grepwc -l

查看PHP-FPM状态页(需要先开启pm.status_path)

curl http://127.0.0.1:9000/status

状态页会显示`idle processes`为0,`active processes`等于`max children`。

解决: 调大`pm.max_children`,但要看服务器内存。每个PHP-FPM进程大约吃30-80MB内存(看你的应用有多重),算一下服务器能承载多少个:
; php-fpm.d/www.conf

pm = dynamic pm.max_children = 100 pm.start_servers = 30 pm.min_spare_servers = 20 pm.max_spare_servers = 70 pm.max_requests = 1000

`pm.max_requests = 1000`也很关键。设置后每个worker处理1000个请求就自动重启,防止内存泄漏把进程搞成僵尸。

第三种:后端服务直接挂了

现象: 全量502,没有任何请求能正常处理。Nginx日志里是`Connection refused`。 原因: upstream服务进程崩了、没启动、或者端口没监听。 排查:
# 检查后端服务是否在运行

systemctl status your-backend-service

检查端口是否在监听

ss -tlnpgrep :8080

手动访问后端,看能不能通

curl -v http://127.0.0.1:8080/health

解决: 把后端服务拉起来。如果反复崩,去看后端服务的日志找崩溃原因。OOM、配置错误、代码bug都有可能。`journalctl -u your-backend-service --since "1 hour ago"`能帮你快速定位。

第四种:DNS解析失败

现象: Nginx配置里用了域名作为upstream地址,某些时候502,某些时候又正常。 原因: Nginx在启动时解析域名并缓存IP,如果上游服务的IP变了(比如容器化部署),Nginx还在连旧的IP。 排查:
# 看Nginx错误日志

grep "could not resolve" /var/log/nginx/error.log grep "host not found" /var/log/nginx/error.log

手动解析看当前DNS返回什么

nslookup your-upstream.example.com dig your-upstream.example.com

解决: 如果用域名做upstream,配上`resolver`指令并开启定期解析:
resolver 8.8.8.8 114.114.114.114 valid=30s;

resolver_timeout 5s;

location / { set $upstream_addr your-backend.example.com; proxy_pass http://$upstream_addr; }

用了`set`变量之后,Nginx会在每次请求时重新解析域名(受`valid`控制缓存时间)。不用变量的话,Nginx只在启动时解析一次,后面IP怎么变它都不知道。

不过说实话,生产环境我更推荐用IP+端口或者内部DNS服务(比如Consul、CoreDNS),别依赖外部DNS做服务发现。

第五种:连接数耗尽

现象: 502和504交替出现,`netstat`显示大量`TIME_WAIT`或`CLOSE_WAIT`连接。 原因: Nginx和upstream之间的连接数达到了上限,或者系统层面的文件描述符/端口资源耗尽。 排查:
# 查看Nginx到upstream的连接状态分布

ss -s

查看TIME_WAIT数量

ss -tan state time-waitwc -l

查看当前进程的fd使用量

ls /proc/$(cat /var/run/nginx.pid)/fdwc -l
cat /proc/$(cat /var/run/nginx.pid)/limitsgrep "open files"
解决: 两个方向,一个是调Nginx的`worker_connections`和`worker_rlimit_nofile`:
worker_rlimit_nofile 65535;

events { worker_connections 4096; }

另一个是优化keepalive复用连接,减少频繁建连的开销(第七种会详细说)。

如果是`TIME_WAIT`堆积的问题,系统层面可以开启连接复用:

# /etc/sysctl.conf

net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 15

第六种:buffer溢出

现象: 后端返回大量数据时502,普通小请求完全正常。Nginx错误日志里有`upstream sent too big header`。 原因: 后端返回的响应头或响应体超过了Nginx的buffer大小限制。 排查:
grep "upstream sent too big" /var/log/nginx/error.log | tail -5
grep "client intended to send too large body" /var/log/nginx/error.logtail -5
解决: 根据日志提示调大对应的buffer:
location /api/ {

proxy_buffer_size 16k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_max_temp_file_size 0;

# 如果是响应头太大(比如Cookie/Set-Cookie很长) proxy_buffer_size 32k; }

`proxy_max_temp_file_size 0`的意思是当响应体超过内存buffer时,不写磁盘临时文件。这样做可以避免磁盘IO成为瓶颈,但代价是会阻塞后端——后端必须等Nginx把数据发给客户端才能继续。根据你的场景权衡。

第七种:keepalive配置不当

现象: 高并发下间歇性502,后端服务本身健康检查通过,但Nginx就是连不上。 原因: Nginx到upstream的keepalive长连接没有正确配置,导致每次请求都要重新建TCP连接。建连成本在高并发下被放大,来不及处理就超时了。 排查: 看Nginx到后端的连接建立频率:
# 抓包看SYN包的频率

tcpdump -i any -n 'host your-upstream-ip and tcp[tcpflags] & tcp-syn != 0' -c 100

如果高并发下还在疯狂建连,说明keepalive没生效。

解决: 在upstream块里配置keepalive:
upstream backend {

server 127.0.0.1:8080; keepalive 128; # 保持128个空闲长连接 keepalive_timeout 60s; keepalive_requests 1000; }

server { location / { proxy_http_version 1.1; proxy_set_header Connection ""; proxy_pass http://backend; } }

这里有个坑必须注意:`proxy_http_version 1.1`和`proxy_set_header Connection ""`必须同时配。HTTP/1.0不支持keepalive,而Nginx默认用HTTP/1.0连upstream。`Connection ""`是清掉Connection头的默认值(默认会发`Connection: close`),告诉upstream保持连接。这两个不配,keepalive形同虚设。

排查502的通用思路

其实不管哪种502,排查套路是一样的:

1. 看Nginx错误日志。`/var/log/nginx/error.log`是一切问题的起点。日志里的关键字决定了你接下来往哪个方向走。 2. 确认upstream状态。端口在不在、服务活没活、能不能连通。 3. 看系统资源。CPU、内存、文件描述符、连接数,哪个到了瓶颈。 4. 看配置。timeout、buffer、keepalive这些参数是否合理。

502不复杂,复杂的是你得在2分钟内找到根因然后恢复服务。所以平时多做演练,把这些排查命令练到形成肌肉记忆。

另外,强烈建议在Nginx配置里加上upstream健康检查:

upstream backend {

server 127.0.0.1:8080 max_fails=3 fail_timeout=30s; }

`max_fails=3`表示连续3次请求失败就把这个节点标记为不可用,`fail_timeout=30s`表示30秒后再试。这样即使后端挂了,Nginx也不会反复往死服务上送请求,直接返回502并快速失败,避免了雪崩。


【放心,我们兜底】

不管你是自己尝试修复,还是需要专业人员上门,易云城IT服务都给你托底。修不好不收费,修好了质保期内随时找我。

📞 服务热线:13708730161 💬 微信:eyc1689 📧 邮箱:service@eycit.com 🌐 https://www.eycit.com

您身边的IT专家。

上一篇
MySQL死锁排查全流程:从一条慢查询到根因定位...
下一篇
Linux服务器CPU 100%排查实录:从top到火焰...