在 PHP 面试中,当面试官问到“你遇到过 502 或 504 吗?怎么排查的?”时,他考察的绝不仅仅是你是否会用 nginx -t 或 systemctl restart php-fpm。这道题背后是一整条从 Nginx 到 PHP-FPM 再到 PHP 脚本执行的知识链:进程模型、通信机制、超时配置、日志体系以及系统资源监控。本文将从 PHP-FPM 的进程模型讲起,逐步展开 502/504 的故障定位全流程,帮助你在面试中给出体系化的回答。
一、PHP-FPM 进程模型:面试必知的核心
PHP-FPM 是 PHP FastCGI 进程管理器的缩写,它实现了 FastCGI 协议,并提供了进程管理能力。理解它的进程模型是定位所有相关故障的基础。
1.1 Master 与 Worker 进程
PHP-FPM 启动后会创建一个 Master 进程和若干个 Worker 进程:
- Master 进程:负责监听端口或 Unix Socket、管理 Worker 进程的生命周期(fork、回收、重启)、读取并分发配置。它不直接处理请求。
- Worker 进程:实际处理来自 Nginx 的 FastCGI 请求,执行 PHP 脚本,返回响应。每个 Worker 在同一时刻只能处理一个请求。
当 Nginx 将请求通过 FastCGI 协议转发给 PHP-FPM 时,Master 进程负责将连接分配给空闲的 Worker。如果没有空闲 Worker,请求会进入等待队列(backlog),直到有 Worker 空闲或超时。
1.2 三种进程管理模式
PHP-FPM 的 pm 配置决定了 Worker 进程的管理方式,面试中常被追问:
- static(静态):启动时固定创建
pm.max_children个 Worker,不增不减。适合内存充足、流量稳定的场景,响应最快,但资源占用固定。 - dynamic(动态):根据负载动态调整 Worker 数量。由
pm.start_servers、pm.min_spare_servers、pm.max_spare_servers、pm.max_children共同控制。适合流量波动较大的场景。 - ondemand(按需):空闲时不保留 Worker,有请求时才 fork。节省内存,但请求突增时 fork 有延迟。适合低流量或内存敏感的环境。
关键点:pm.max_children 决定了并发处理能力的上限。如果所有 Worker 都在忙碌,新请求只能排队,排队超时就会触发 504。
1.3 通信方式:TCP 与 Unix Socket
Nginx 与 PHP-FPM 之间有两种通信方式:
- TCP:如
127.0.0.1:9000,跨主机可用,但有网络协议栈开销。 - Unix Socket:如
/run/php-fpm.sock,本机通信,性能更好,但需要注意权限和 backlog 配置。
在 listen 指令后可以跟 backlog 参数,表示等待队列的长度。如果队列满了,新连接会被拒绝,Nginx 就会返回 502。
二、502 与 504 的本质区别
很多候选人会把 502 和 504 混为一谈,面试中能清晰区分它们是加分项。
- 502 Bad Gateway:Nginx 作为网关,无法从上游(PHP-FPM)获得有效响应。常见原因包括:PHP-FPM 进程崩溃、Socket 文件不存在或权限错误、Worker 全部挂掉、FastCGI 连接被拒绝。
- 504 Gateway Timeout:Nginx 成功连接到了上游,但在指定时间内没有收到完整响应。常见原因包括:PHP 脚本执行时间过长、Worker 被慢请求占满导致排队、数据库慢查询、外部 API 阻塞。
一句话总结:502 是“连不上或连上了但对方挂了”,504 是“连上了但等太久”。
三、故障定位全流程
面试中回答排查步骤时,建议按“从外到内、从现象到根因”的顺序展开。
3.1 第一步:确认现象与影响面
- 是所有请求都失败,还是特定接口?
- 是持续失败,还是偶发?
- 是否伴随流量突增或发布变更?
这一步决定了排查方向:全站 502 通常是 PHP-FPM 挂了或 Socket 配置错误;单接口 504 通常是该接口逻辑慢或依赖服务慢。
3.2 第二步:检查 Nginx 错误日志
Nginx 的 error_log 是最直接的线索。典型日志:
connect() to unix:/run/php-fpm.sock failed (2: No such file or directory)
upstream timed out (110: Connection timed out) while reading response header from upstream
No such file or directory:Socket 文件不存在,PHP-FPM 可能没启动或监听路径不一致。Connection refused:PHP-FPM 没在监听,或端口不对。upstream timed out:504 的典型日志,说明连接成功但响应超时。
3.3 第三步:检查 PHP-FPM 状态与进程
systemctl status php-fpm
ps aux | grep php-fpm
观察 Worker 进程数量是否正常。如果 Worker 数量为 0 或远低于 pm.max_children,说明进程可能不断崩溃重启。此时查看 PHP-FPM 的 error_log(通常在 /var/log/php-fpm/error.log 或 /var/log/php-fpm.log),关注:
WARNING: [pool www] server reached pm.max_children settingWARNING: [pool www] seems busychild exited on signal 11(段错误)
3.4 第四步:检查慢日志与脚本执行
PHP-FPM 支持慢日志配置:
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slow.log
慢日志会记录执行超过阈值的脚本及其调用栈,是定位 504 的利器。通过 slow.log 可以快速找到是哪个函数或外部调用拖慢了请求。
3.5 第五步:检查系统资源
- 内存:
free -h,如果内存耗尽,OOM Killer 可能杀掉 Worker 进程,导致 502。 - CPU:
top,CPU 饱和会导致所有请求变慢,进而 504。 - 文件描述符:
ulimit -n,如果 FD 耗尽,新连接无法建立。 - 连接数:
ss -s或netstat,查看 Socket 队列是否溢出。
3.6 第六步:检查超时配置链
502/504 往往与多层超时配置不匹配有关。需要检查:
- Nginx
fastcgi_read_timeout:Nginx 等待 PHP-FPM 响应的超时。 - Nginx
fastcgi_connect_timeout:连接 PHP-FPM 的超时。 - PHP-FPM
request_terminate_timeout:Worker 处理单个请求的最大时间。 - PHP
max_execution_time:脚本最大执行时间。 - 上游服务(数据库、Redis、外部 API)的超时。
如果 Nginx 的 fastcgi_read_timeout 小于 PHP 的实际执行时间,就会 504。如果 PHP-FPM 的 request_terminate_timeout 过短,Worker 会被杀掉,可能触发 502。
四、面试中的体系化回答模板
当被问到“如何排查 502/504”时,可以这样组织回答:
- 先定性:502 是连接或进程问题,504 是超时问题。
- 看日志:Nginx error_log 定位错误类型,PHP-FPM error_log 和 slow.log 定位具体脚本。
- 查进程:确认 Worker 数量、是否频繁重启、是否达到 max_children。
- 查资源:内存、CPU、FD、连接队列。
- 查配置:超时链是否匹配,backlog 是否足够。
- 复现与验证:通过压测或日志回放确认根因,调整配置后观察。
五、总结
PHP-FPM 的进程模型决定了它的并发能力和故障模式。Master 管理 Worker,Worker 逐个处理请求,pm.max_children 是并发上限,backlog 是等待队列,超时配置是多层协作的结果。502 通常指向进程或连接层面的失败,504 则指向响应时间超出预期。掌握从 Nginx 到 PHP-FPM 再到系统资源的完整排查链路,不仅能解决实际问题,也能在面试中展现出扎实的工程能力。
未经允许不得转载:任鹏个人博客 » PHP 面试精讲:PHP-FPM 进程模型与 502/504 故障定位全流程

