nginx 502 Bad Gateway 逐步排查:从 upstream 超时到 PHP-FPM 假死 核心要点图解,502 错误根源通常是 upstream 超时或 PHP-FPM 假死,先查错误日志定位方向。;用 ss 和 ps 检查 PHP-FPM 进程状态,确认是否假死或资源耗尽。;调整 fastcgi_read_timeout 和 pm.max_children 可解决多数超时问题。;定期监控 PHP-FPM 状态页和慢日志,预防 502 复发。
nginx 502 Bad Gateway 逐步排查:从 upstream 超时到 PHP-FPM 假死 · 核心要点一图读懂(AegisX)

核心要点(TL;DR)

  • 502 错误根源通常是 upstream 超时或 PHP-FPM 假死,先查错误日志定位方向。
  • 用 ss 和 ps 检查 PHP-FPM 进程状态,确认是否假死或资源耗尽。
  • 调整 fastcgi_read_timeout 和 pm.max_children 可解决多数超时问题。
  • 定期监控 PHP-FPM 状态页和慢日志,预防 502 复发。

网站突然无法访问,浏览器显示 502 Bad Gateway,用户投诉不断,而你却毫无头绪?作为运维或站长,nginx 502 错误堪称“常客”,但背后原因却可能千差万别。本文将从实战角度,带你逐步排查从 upstream 超时到 PHP-FPM 假死的各类诱因,提供可落地的命令与检查清单,助你快速恢复服务。

1. 理解 502 错误:nginx 与上游的通信故障

502 Bad Gateway 表示 nginx 作为反向代理,从上游服务器(如 PHP-FPM、Tomcat 等)收到了无效响应。常见原因包括上游进程崩溃、超时、连接被拒绝或返回了不符合协议的响应。对于 PHP 站点,PHP-FPM 是首要怀疑对象。

关键点:502 不是 nginx 自身故障,而是上游出了问题。因此排查重点应放在上游服务的状态和日志上。

2. 第一步:检查 nginx 错误日志,定位方向

nginx 错误日志是排查 502 的起点。默认路径通常为 /var/log/nginx/error.log,使用以下命令实时查看:

tail -f /var/log/nginx/error.log

触发一次 502 请求,观察日志输出。常见关键字及含义:

日志关键字可能原因
upstream prematurely closed connection上游进程崩溃或主动断开
upstream timed out上游处理超时
connect() failed (111: Connection refused)上游服务未启动或端口不对
no live upstreams所有上游节点均不可用

根据日志提示,可初步判断是超时、进程崩溃还是配置错误。例如,若出现 upstream timed out,则重点检查超时设置和上游性能;若出现 Connection refused,则检查 PHP-FPM 是否运行。

3. 第二步:检查 PHP-FPM 进程与端口状态

确认 PHP-FPM 是否存活是排查 502 的关键。执行以下命令:

ps aux | grep php-fpm
ss -lntp | grep php

若进程不存在,说明 PHP-FPM 已停止,需启动服务:systemctl start php-fpm(或对应版本)。若进程存在但端口无监听,可能是配置错误或启动失败,检查 PHP-FPM 错误日志 /var/log/php-fpm/error.log。

若进程和端口均正常,但 502 仍间歇出现,则需考虑 PHP-FPM 假死:进程虽在,但无法处理新请求。此时可通过 ss -lntp 查看监听队列是否已满(Send-Q 持续大于 0),或使用 strace 跟踪进程状态。

4. 第三步:深入 PHP-FPM 假死与资源耗尽

PHP-FPM 假死常因进程池耗尽或脚本阻塞导致。检查以下方面:

  • 进程数限制:查看 pm.max_children 设置,若达到上限,新请求将排队直至超时。通过 ps aux | grep php-fpm | wc -l 统计当前进程数,与配置对比。
  • 慢日志分析:启用 request_slowlog_timeout 和 slowlog,定位执行缓慢的脚本。例如:slowlog = /var/log/php-fpm/slow.log,然后分析日志中的堆栈。
  • 系统资源:使用 top、free -m 检查 CPU 和内存是否耗尽,内存不足可能导致进程被 OOM Killer 终止。

若发现进程数达到上限,可临时增加 pm.max_children 并重启 PHP-FPM 缓解,但需根据服务器内存合理设置,避免内存耗尽。

5. 第四步:调整超时参数与连接配置

超时是 502 的常见诱因。检查 nginx 和 PHP-FPM 的超时设置是否匹配:

  • nginx 侧:fastcgi_connect_timeout、fastcgi_send_timeout、fastcgi_read_timeout 默认 60s,若脚本执行时间较长,可适当增加,如 fastcgi_read_timeout 300s;。
  • PHP-FPM 侧:request_terminate_timeout 应大于 nginx 的 fastcgi_read_timeout,避免 PHP 提前终止。例如设置为 request_terminate_timeout = 300s。

同时,检查 fastcgi_buffers 和 fastcgi_buffer_size,若响应头过大可能导致 502,可适当调大。

6. 第五步:检查 upstream 配置与网络连通性

若使用 upstream 块定义后端,检查配置是否正确:

upstream php_backend {
    server unix:/run/php-fpm.sock;
    # 或 server 127.0.0.1:9000;
}

确认 socket 文件路径或 IP:端口 与 PHP-FPM 监听一致。使用 telnet 127.0.0.1 9000 或 nc -zv 127.0.0.1 9000 测试连通性。若使用 Unix socket,检查文件权限(通常需 nginx 用户可读写)。

此外,检查防火墙规则是否拦截了本地回环通信,尤其是使用 TCP 端口时。

7. 第六步:防护建议与长效监控

解决当前故障后,建立预防机制避免复发:

  • 启用 PHP-FPM 状态页(pm.status_path = /status),通过 nginx 限制访问,定期监控 active processes 和 listen queue。
  • 配置日志监控告警,对 nginx 错误日志中的 502 关键字和 PHP-FPM 的 max_children 警告实时通知。
  • 使用 AegisX 的实时监控与告警能力,对 PHP-FPM 进程数、内存使用和请求队列进行持续跟踪,提前发现潜在瓶颈。

定期审查 pm.max_children 和超时参数,结合压力测试调整至最优值。

行动建议

下次遇到 502,按以下清单快速排查:

  1. 查 nginx 错误日志,确定关键字。
  2. 查 PHP-FPM 进程与端口状态。
  3. 查进程数是否达到上限,分析慢日志。
  4. 核对 nginx 与 PHP-FPM 超时设置。
  5. 检查 upstream 配置与网络连通性。

立即收藏本文,并分享给团队成员,让 502 不再成为难题。

常见问题(FAQ)

nginx 502 错误和 504 错误有什么区别?

502 Bad Gateway 表示 nginx 作为网关从上游服务器(如 PHP-FPM)收到了无效响应,常见于上游进程崩溃或假死;504 Gateway Timeout 则是上游服务器响应超时。简单说,502 是连接上了但响应异常,504 是根本没在限定时间内收到响应。排查时 502 更关注上游进程状态,504 更关注超时设置和上游性能。

如何快速判断是不是 PHP-FPM 假死导致的 502?

执行 `ps aux | grep php-fpm` 查看进程是否存在,再用 `ss -lntp | grep php` 检查监听端口是否正常。如果进程在但端口无响应,或进程数达到 pm.max_children 上限,基本可判定为假死。此时可尝试重启 PHP-FPM 服务临时恢复,并进一步分析日志和资源使用情况。

nginx 错误日志中哪些关键字提示 502 原因?

常见关键字包括 `upstream prematurely closed connection`(上游提前关闭连接)、`upstream timed out`(上游超时)、`connect() failed`(连接失败)和 `no live upstreams`(无可用上游)。根据这些信息可判断是超时、进程崩溃还是网络问题。结合 PHP-FPM 错误日志中的 `WARNING: [pool www] server reached pm.max_children` 等提示,能更准确定位。

调整 PHP-FPM 的 pm.max_children 有什么注意事项?

pm.max_children 决定同时处理的请求数,设置过小会导致请求排队超时,过大则可能耗尽内存。建议根据服务器内存和单个 PHP 进程平均内存计算:`pm.max_children = 可用内存 / 单个进程内存`。调整后需重启 PHP-FPM,并监控内存使用和 502 发生率。同时配合 pm.max_requests 防止内存泄漏。

如何监控 PHP-FPM 状态以预防 502?

启用 PHP-FPM 状态页(在 pool 配置中设置 `pm.status_path = /status`),并通过 nginx 配置访问权限。定期检查 `active processes`、`listen queue` 和 `max children reached` 指标。结合监控工具(如 Prometheus + php-fpm_exporter)设置告警,当队列长度持续大于 0 或达到 max_children 时触发通知,提前干预避免 502。