Nginx 502 Bad Gateway 后端到底挂了没有
nginx error_log /var/log/nginx/error.log warn; # 或者 debug
进入日志目录查看最近502相关的错误:
```bash
tail -f /var/log/nginx/error.log | grep "502\|upstream"
对照下表快速解读:
| 日志关键字 | 最可能的原因 | 后端状态 |
|---|---|---|
connect() failed (111: Connection refused) |
后端未监听端口 | 挂了 / 未启动 |
connect() failed (110: Connection timed out) |
防火墙拦截或网络不通 | 可能网络问题,非进程问题 |
upstream timed out (110: Connection timed out) |
后端处理超时 | 活但慢 |
upstream prematurely closed connection |
后端进程崩溃或异常退出 | 不稳定 |
no live upstreams |
所有后端服务器都被标记为不可用 | 全部挂了或健康检查失败 |
recv() failed (104: Connection reset by peer) |
后端主动重置连接 | 活但不正常 |
后端是否存活:一套有效检查命令
不要仅凭 ps 看进程就下结论。按照以下顺序逐步确认后端真实状态。
检查端口监听状态
ss -tlnp | grep :9000
如果没有任何输出,服务确实未启动。PHP-FPM 一般监听9000端口,其他服务替换为对应端口。
手动模拟一次请求
绕过Nginx,直接向后端发起请求,观察是否能得到正常响应。
对于HTTP后端(如Gunicorn、Tomcat):
curl -v http://127.0.0.1:8080/health-check
对于FastCGI后端(如PHP-FPM):
cgi-fcgi -bind -connect 127.0.0.1:9000 /status
或使用更简单的脚本模拟:
echo -e "GET /index.php HTTP/1.1\r\nHost: localhost\r\n\r\n" | nc 127.0.0.1 9000
(注意:PHP-FPM 需要配合 SCRIPT_FILENAME 等参数构造完整的fastcgi请求包,可以用 cgi-fcgi 或 curl --unix-socket)
检查进程数量与状态
ps auxf | grep php-fpm
关注 php-fpm: pool www 子进程是否全部处于 S (睡眠)状态,如果大量处于 R (运行) 或 D (不可中断睡眠),说明进程繁忙。若 TIME 列累计CPU时间过大,可能存在死循环。
查看系统资源瓶颈
- 文件描述符:
ulimit -n(进程级别)和/proc/sys/fs/file-max(系统级) - 连接追踪:
cat /proc/sys/net/netfilter/nf_conntrack_count是否接近nf_conntrack_max - 内存/CPU:
top或htop查看是否有 OOM Killer 记录 (dmesg | grep -i kill)
常见后端(以PHP-FPM为例)的502解决方案
1. 端口或socket配置错误
确认Nginx与PHP-FPM的通信方式一致。如果用unix socket,确保两边路径相同且权限正确:
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
Socket文件必须可读可写,通常赋权:listen.mode = 0660 并在同一个用户组。
2. PHP-FPM进程数不足
pm.max_children 设得太低,请求排队导致超时。适当增加,但需结合服务器内存:
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
同时增大 request_terminate_timeout 防止单个请求永久占用。
3. 请求超时时间不匹配
Nginx的 fastcgi_read_timeout 必须大于 PHP 的 max_execution_time,避免PHP还在执行,Nginx已断开连接。
4. 后端返回头过大或缓冲不足
如果后端返回大量数据或响应头,可能突破Nginx的 proxy_buffer_size 或 fastcgi_buffer_size,导致连接中断。调大缓冲:
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;