常见 502/504 故障排查
常见 502/504 故障排查
写在前面
Nginx 作为反向代理,最常见的故障就是 5xx。本篇是故障排查速查表——涵盖 502/503/504 的所有常见原因、排查步骤、修复方案,以及 5 个真实生产故障的完整复盘。
一、5xx 状态码含义
| 状态码 | 含义 | 通常原因 |
|---|---|---|
| 500 | Internal Server Error | 后端代码错误 |
| 502 | Bad Gateway | Nginx 收不到 upstream 有效响应 |
| 503 | Service Unavailable | upstream 主动拒绝 / 限流 |
| 504 | Gateway Timeout | Nginx 等 upstream 超时 |
502 和 504 是 Nginx 反代的"特产"——直接访问后端没问题,通过 Nginx 就 502/504。
二、502 Bad Gateway
2.1 含义
Nginx 连不上 upstream,或者连接被切断,或者响应格式错误。
2.2 常见原因
- upstream 服务没启动
- upstream 端口配错
- upstream 主动断开连接(进程被 kill、OOM)
- 响应头过大(超过
proxy_buffer_size) - 后端响应了不完整的 HTTP(程序 bug)
- upstream 用了 HTTP/2,Nginx 用 HTTP/1.1 代理
2.3 排查步骤
# 第一步:upstream 是否在监听
ss -tlnp | grep 3000
# LISTEN 0 511 0.0.0.0:3000 ...
# 第二步:从 Nginx 机器直接 curl upstream
curl -i http://10.0.0.1:3000/health
# HTTP/1.1 200 OK
# ...
# 第三步:Nginx 错误日志
tail -f /var/log/nginx/error.log
# 2024/07/15 14:23:01 [error] 1234#0: *5678 connect() failed (111: Connection refused) while connecting to upstream
2.4 经典错误信息
| 错误信息 | 原因 |
|---|---|
connect() failed (111: Connection refused) |
upstream 没起 / 端口错 |
connect() failed (113: No route to host) |
网络层问题 |
upstream prematurely closed connection |
upstream 主动断开 |
invalid header |
响应头格式错误 / 过大 |
no live upstreams |
upstream 全部标记为 down |
SSL_do_handshake() failed |
上游 HTTPS 证书问题 |
2.5 案例 1:响应头过大导致 502
现象:上传图片的接口偶发 502。
根因:proxy_buffer_size 默认 4k,响应头超过 4k 就报错。
修复:
location /api/upload {
proxy_pass http://backend;
proxy_buffer_size 16k; # 调大
proxy_buffers 8 32k;
}
2.6 案例 2:upstream OOM 被杀
现象:高峰时段 502 间歇性出现。
日志:
upstream prematurely closed connection
排查:
# 看 dmesg
dmesg | grep -i "killed process"
# [12345.678] Killed process 12345 (node) total-vm:1234567kB, anon-rss:524288kB
根因:Node 应用 OOM 被杀。
修复:
# docker-compose
services:
api:
deploy:
resources:
limits:
memory: 1G
或者修代码的内存泄漏。
三、504 Gateway Timeout
3.1 含义
Nginx 等 upstream 响应超时。
3.2 常见原因
- 后端处理慢(数据库慢查询、外部 API 卡住)
proxy_read_timeout设得太短- upstream 死锁
- upstream 等待中,CPU 100%
3.3 排查步骤
# 1. 后端响应慢在哪
# 从 Nginx 机器直接 curl
time curl http://10.0.0.1:3000/slow-api
# real 0m 30.01s ← 超时!
# 2. 错误日志
tail /var/log/nginx/error.log
# *5678 upstream timed out (110: Connection timed out) while reading response header from upstream
3.4 经典错误信息
| 错误信息 | 原因 |
|---|---|
upstream timed out (110: Connection timed out) |
整个连接超时 |
upstream timed out (110: Connection timed out) while reading response header |
等响应头超时 |
upstream timed out while reading response |
等响应体超时 |
3.5 案例 3:数据库慢查询导致 504
现象:下午 2 点开始批量 504,持续 20 分钟。
排查:
# Prometheus 看 MySQL
mysql_global_status_slow_queries
根因:一个定时任务在跑大报表查询,锁住 orders 表。
修复:
-- 给大查询设超时
SET SESSION MAX_EXECUTION_TIME = 30000; -- 30 秒
-- 应用层加超时
SELECT /*+ MAX_EXECUTION_TIME(30000) */ ...
Nginx 端:
location /api/orders {
proxy_pass http://order_service;
proxy_read_timeout 35s; # 比后端超时略长
}
3.6 案例 4:WebSocket 长连接 504
现象:WebSocket 连接保持 1 分钟后 504。
根因:proxy_read_timeout 默认 60s,WebSocket 长连接超时。
修复:
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s; # 1 小时
proxy_send_timeout 3600s;
}
四、503 Service Unavailable
4.1 含义
upstream 主动拒绝请求,或被限流。
4.2 常见原因
- 限流触发
- upstream 维护中
- upstream 启动中
- 健康检查失败
4.3 案例 5:健康检查失败导致 503
现象:部分请求 503,日志 no live upstreams。
根因:健康检查路径配错。
# 错误 - 后端没有这个路径
location / {
health_check interval=5s uri=/health uri_is_redirect;
}
# 后端实际是 /api/health
修复:对齐路径。
location / {
health_check interval=5s uri=/api/health;
}
五、4xx 错误
虽然不是 5xx,但生产中也常见,顺便讲讲。
5.1 400 Bad Request
- 请求头过大(超过
large_client_header_buffers) - 请求格式错误
- 客户端连接断开
5.2 403 Forbidden
- IP 黑名单
- 文件权限
allow/deny规则
5.3 404 Not Found
try_files没匹配root路径错alias没结尾/
5.4 413 Request Entity Too Large
client_max_body_size限制
5.5 499 Client Closed Request
Nginx 特有:客户端主动断开请求。常见于响应太慢,客户端超时。
# 看 499 比例
awk '$9 == 499 {count++} END {print count}' /var/log/nginx/access.log
如果 499 多,说明:
- 后端响应慢
- 客户端 timeout 太短
六、系统化排查流程
6.1 五步排查法
Step 1: 看错误日志
tail -f /var/log/nginx/error.log | grep -E "(error|crit|emerg)"
Step 2: 看访问日志
tail -f /var/log/nginx/access.log | grep " 502 \| 503 \| 504 "
Step 3: 直接访问 upstream
# 绕过 Nginx,直接打后端
curl -i http://10.0.0.1:3000/api/orders
如果直接访问没问题,问题在 Nginx。
如果直接访问也 5xx,问题在后端。
Step 4: 看 upstream 状态
# 系统资源
top
free -h
df -h
# 后端进程
ps aux | grep node
Step 5: 网络层
# 端口通不通
nc -zv 10.0.0.1 3000
# TCP 连接
ss -tan | grep 3000
# 抓包
tcpdump -i any -nn -s 0 -w /tmp/cap.pcap host 10.0.0.1 and port 3000
6.2 配置健康检查
upstream backend {
server 10.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 10.0.0.2:3000 max_fails=3 fail_timeout=30s;
}
server {
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 10s;
}
}
自动 failover:一个 upstream 挂掉,流量自动转走。
6.3 配置错误页面
server {
error_page 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
internal;
}
}
6.4 监控告警
# Prometheus blackbox_exporter
- name: nginx_errors
rules:
- alert: Nginx502High
expr: |
sum(rate(nginx_http_requests_total{status="502"}[5m])) > 1
for: 5m
labels:
severity: critical
- alert: Nginx504High
expr: |
sum(rate(nginx_http_requests_total{status="504"}[5m])) > 1
for: 5m
labels:
severity: critical
七、Nginx 配置本身的错误
不是后端问题,是 Nginx 配错。
7.1 配置文件语法错误
nginx -t
# nginx: [emerg] unexpected "}" in /etc/nginx/nginx.conf:45
7.2 配置 reload 失败
nginx -s reload
# nginx: [error] invalid PID number "" in "/run/nginx.pid"
# 解决
sudo nginx -c /etc/nginx/nginx.conf
7.3 include 文件权限问题
nginx -t
# nginx: [emerg] open() "/etc/nginx/conf.d/api.conf" failed (13: Permission denied)
chmod 644 /etc/nginx/conf.d/api.conf
chown root:root /etc/nginx/conf.d/api.conf
八、调试技巧
8.1 debug 日志
error_log /var/log/nginx/debug.log debug;
需要编译时带 --with-debug。
8.2 tcpdump 抓包
tcpdump -i any -nn -A -s 0 port 443 and host 1.2.3.4 | head -100
8.3 strace 跟踪 worker
strace -p $(pgrep -f "nginx: worker") -e trace=network,read,write -f
⚠️ strace 性能影响大,只在调试时用。
九、故障应急手册
9.1 502 应急
#!/bin/bash
# emergency-502.sh
# 1. 看 upstream 状态
echo "=== Upstream Status ==="
systemctl status my-app || echo "App not running"
# 2. 看连接
echo "=== Connections ==="
ss -tan | grep 3000 | head -20
# 3. 看错误日志最近 100 行
echo "=== Recent Errors ==="
tail -100 /var/log/nginx/error.log
# 4. 重启 upstream
echo "=== Restarting App ==="
systemctl restart my-app
# 5. 验证恢复
sleep 5
curl -i http://10.0.0.1:3000/health
9.2 一键回滚
#!/bin/bash
# rollback.sh
# 备份当前配置
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
# 用上一个版本
cp /etc/nginx/nginx.conf.last-working /etc/nginx/nginx.conf
# 测试
nginx -t && nginx -s reload
echo "Rolled back to last working config"
十、本篇小结
| 错误 | 含义 | 第一排查 |
|---|---|---|
| 502 | 收不到 upstream 响应 | upstream 状态 / 端口 |
| 503 | upstream 拒绝 / 限流 | 限流配置 / 健康检查 |
| 504 | 等 upstream 超时 | proxy_read_timeout / 后端性能 |
| 499 | 客户端断开 | 后端响应慢 |
| 排查步骤 | 命令 |
|---|---|
| 看错误日志 | tail /var/log/nginx/error.log |
| 看 5xx 状态码 | grep " 50[234] " access.log |
| 直接打后端 | curl http://upstream/api |
| 看进程 | ps aux | grep app |
| 抓包 | tcpdump -i any port 443 |
下一篇是 Nginx 系列的最后一篇,日志分析与可视化——用 GoAccess 和 ELK 找爬虫、分析流量模式。