FastCGI 和 PHP-FPM 到底是什么关系
这题在 PHP 面试里非常常见,但也非常容易答混。
很多人会把这几个概念混在一起:
- CGI
- FastCGI
- PHP-FPM
- Nginx
结果就是:
- 只会说一句“PHP-FPM 是 PHP 解释器”
- 或者说“FastCGI 就是 PHP-FPM”
- 再或者只背
Nginx + PHP-FPM
这些都不算真正讲清楚。
如果你想把这题答得更像“做过线上系统的人”,最好把它拆成三层:
- 它们各自是什么
- 它们怎么协作
- 出问题时怎么分析和解决
一、先把 3 个概念拆开
1. CGI 是什么
CGI,Common Gateway Interface,本质上是一套“Web Server 怎么把动态请求交给外部程序处理”的老方案。
你可以粗暴理解成:
- Web Server 收到一个动态请求
- 临时启动一个外部进程
- 把请求参数、环境变量、标准输入传给它
- 外部程序处理后,把结果写回标准输出
- Web Server 再把结果返回给客户端
CGI 的优点
- 模型简单
- 语言无关
- 任何能读写标准输入输出的程序都能接进来
CGI 的核心问题
每来一个请求都要新建一个进程,成本太高。
这会带来几个问题:
- 频繁 fork / exec
- 进程创建开销大
- 并发一高就很容易顶不住
所以 CGI 的问题不是“不能用”,而是:
它在高并发 Web 场景下太重了。
二、FastCGI 是什么
FastCGI 可以理解为 CGI 的改良版。
它要解决的核心问题就是:
不要每个请求都临时起一个新进程。
FastCGI 的核心思想
- 外部程序常驻
- Web Server 不再为每个请求反复创建进程
- 双方通过一套协议长期通信
也就是说,FastCGI 不是某个具体软件,而是一种协议和工作方式。
你可以这样记
- CGI:请求来了,临时起进程
- FastCGI:进程提前常驻,请求来了直接交给它处理
FastCGI 解决了什么
- 减少进程创建销毁开销
- 提升吞吐
- 更适合高并发 Web 动态请求
面试里一句很稳的话
FastCGI 本质上是 CGI 的常驻进程化版本,它解决的是“每个请求都起新进程”带来的性能问题。
三、PHP-FPM 是什么
PHP-FPM 全称是 PHP FastCGI Process Manager。
这句话里最关键的不是 PHP,而是:
FastCGI Process Manager
也就是说,PHP-FPM 不是 FastCGI 协议本身,而是:
PHP 在 FastCGI 模式下的进程管理器。
它负责什么
- 维护一组常驻 PHP worker 进程
- 管理这些 worker 的创建、回收和数量上限
- 接收来自 Nginx 的 FastCGI 请求
- 把请求分配给空闲 worker 去执行 PHP 脚本
它不负责什么
- 不负责静态资源分发
- 不负责 HTTPS 连接接入
- 不负责反向代理
- 不负责业务路由
这些一般是 Nginx 做的。
所以三者关系一句话怎么说
FastCGI 是协议,PHP-FPM 是 PHP 的 FastCGI 进程管理器,Nginx 是请求入口和反向代理。
这句一说出来,概念就清楚很多了。
四、Nginx、FastCGI、PHP-FPM 到底怎么协作
很多人会背:
客户端 -> Nginx -> PHP-FPM
这不算错,但还不够细。
更完整的链路应该是:
- 客户端把 HTTP 请求打到 Nginx
- Nginx 判断这是静态资源还是 PHP 动态请求
- 如果是静态资源,Nginx 直接返回
- 如果是 PHP 动态请求,Nginx 按 FastCGI 协议把请求转发给 PHP-FPM
- PHP-FPM 选一个空闲 worker 执行对应 PHP 脚本
- worker 执行完成后,把响应内容返回给 PHP-FPM
- PHP-FPM 再把结果回给 Nginx
- Nginx 最终把 HTTP 响应返回给客户端
这里最容易被问到的点
1. Nginx 为什么不直接执行 PHP
因为 Nginx 本身不是 PHP 解释器,它擅长的是:
- 网络连接处理
- 高并发事件驱动
- 静态资源处理
- 反向代理
而执行 PHP 脚本,需要 PHP 运行时和进程池管理,这正是 PHP-FPM 的职责。
2. FastCGI 在这里扮演什么角色
FastCGI 是 Nginx 和 PHP-FPM 之间通信的语言。
你可以把它理解成:
- HTTP 是浏览器和 Nginx 说话的协议
- FastCGI 是 Nginx 和 PHP-FPM 说话的协议
五、PHP-FPM 内部到底是怎么工作的
这块才是面试官最爱深挖的地方。
1. PHP-FPM 的基本结构
PHP-FPM 一般有两类进程:
- master 进程
- worker 进程
master 进程负责什么
- 读取配置
- 监听端口或 Unix Socket
- 创建和回收 worker
- 平滑重载
- 监控 worker 状态
worker 进程负责什么
- 真正执行 PHP 脚本
- 处理具体请求
一个 worker 在同一时刻通常只处理一个请求。
这句话非常重要,因为它解释了很多线上现象:
- 为什么并发一高,FPM 容易打满
- 为什么
max_children很关键 - 为什么单个慢请求会占住一个 worker
六、为什么 PHP-FPM 是进程池,不是线程池
你可以从历史和稳定性两个角度讲。
1. PHP 的经典 Web 模型更适合多进程隔离
PHP 很长一段时间的经典模型就是:
- 一个请求进入
- worker 执行脚本
- 请求结束后释放大部分运行态
这种模型天然适合通过多个独立进程来隔离请求。
2. 多进程隔离更稳
如果某个 worker 内存泄漏、崩溃、卡死,通常只影响这个 worker,不会把整个服务一起拖死。
3. 这也解释了它的边界
多进程模型虽然稳,但也意味着:
- 进程切换有成本
- 内存占用比线程模型更高
- 共享内存状态不自然
所以 PHP-FPM 的重点不是“单机极致吞吐”,而是:
稳定、可控、隔离性强。
七、pm = static / dynamic / ondemand 到底怎么理解
这是 PHP-FPM 面试里特别爱问的点。
1. static
固定数量的 worker,启动后一直常驻。
特点:
- 响应稳定
- 没有临时拉起进程的抖动
- 内存占用可预估
适合:
- 流量相对稳定
- 机器资源比较充足
2. dynamic
启动一部分 worker,再根据压力在 min_spare_servers 和 max_children 之间动态伸缩。
特点:
- 更平衡
- 线上最常见
适合:
- 大多数常规业务系统
3. ondemand
有请求才拉 worker,空闲久了再回收。
特点:
- 节省内存
- 首次请求可能有拉起开销
适合:
- 低频服务
- 长时间空闲的业务池
面试里怎么一句话讲清
static 更偏稳定,ondemand 更偏省资源,dynamic 是大多数线上系统的折中选择。
八、请求到底是怎么到 worker 的
这块如果能讲清,面试官一般会觉得你不是只背词。
一个请求进来时,大致会发生什么
- Nginx 把 PHP 请求通过 FastCGI 发给 PHP-FPM
- PHP-FPM 把请求放到监听队列
- 空闲 worker 从队列里取到请求
- worker 初始化请求上下文
- worker 执行目标 PHP 脚本
- 业务代码跑完,生成输出
- 输出返回给 Nginx
- 当前 worker 回到空闲状态,等下一次请求
这就引出两个关键点
1. 为什么慢请求会拖垮 FPM
因为慢请求会长时间占住 worker。
如果并发请求越来越多,但每个请求都执行得很慢,就会出现:
- 空闲 worker 越来越少
- 新请求排队
- 队列堆积
- 最后出现超时或
502
2. 为什么 max_children 打满不一定是参数问题
因为真正的根因往往是:
- SQL 慢
- Redis / MySQL / HTTP 外部依赖慢
- 代码里有重逻辑
- 下游超时重试导致雪崩
max_children 只是并发承载上限,不是性能优化本身。
九、线上为什么会出现 502、max_children 打满、队列堆积
这块很适合面试拉开差距,因为它从“背概念”进入“做过排查”。
1. 502 Bad Gateway
常见含义是:
- Nginx 没有从 PHP-FPM 拿到正常响应
常见原因:
- PHP-FPM 没启动
listen的 socket / 端口不通- worker 打满,排队过久
- worker 执行超时或崩溃
- 脚本 fatal error,导致返回异常
这时候该怎么查
先查:
- Nginx error log
- PHP-FPM log
- PHP slow log
- 当前 worker 数和
max_children
而不是一上来就改配置。
2. max_children reached
这个日志的本质是:
当前可用于处理请求的 worker 全被占满了。
这意味着:
- 请求进来的速度,大于请求处理完成的速度
根因可能是:
- 突发流量
- 慢 SQL
- 第三方接口慢
- 某段代码 CPU 特别重
- 机器资源不足
解决思路
不要只说“调大 pm.max_children”。
更稳的回答应该是:
- 先确认是不是短时流量波峰
- 再看慢请求到底卡在数据库、缓存还是外部接口
- 再评估机器内存是否支持更高的 worker 数
- 最后再决定要不要调大
max_children
3. listen queue 堆积
这说明请求已经到 PHP-FPM 入口了,但没有足够快地被 worker 消化。
本质上还是:
- 供给和消费失衡
它通常说明问题不只是“配置小”,更可能是:
- worker 处理太慢
- worker 不够
- 上游流量突增
十、面试里怎么从“分析”讲到“解决”
这块非常关键。
很多人的回答停在:
PHP-FPM 打满了,就调大 max_children。
这个回答太薄。
更好的回答顺序是:
- 先判断是流量问题还是执行变慢
- 看 PHP-FPM 是否真的打满
- 看慢请求卡在哪一层
- 再决定是扩 worker、优化 SQL、加缓存,还是拆异步
一个更像做过线上系统的说法
如果线上出现 PHP-FPM 打满,我不会第一时间只改参数。我会先看 max_children 是否打满、slowlog 里卡的是 SQL 还是外部接口、Nginx 到 FPM 的队列有没有堆积,再决定是优化慢请求、拆异步、加缓存,还是在机器资源允许的前提下调大进程池。
这句话很加分,因为它体现的是排查顺序。
十一、FastCGI 参数和 PHP 执行上下文
这块不一定每次都会问,但问到了很加分。
当 Nginx 把请求发给 PHP-FPM 时,除了把请求体发过去,还会带一组 FastCGI 参数,比如:
SCRIPT_FILENAMEREQUEST_METHODQUERY_STRINGCONTENT_TYPECONTENT_LENGTH
PHP-FPM 的 worker 会基于这些参数构造 PHP 运行环境,例如:
$_SERVER$_GET$_POST
所以你可以理解成:
Nginx 负责把 HTTP 请求转换成 FastCGI 环境,PHP-FPM 再基于这些环境去执行 PHP 脚本。
十二、为什么静态资源一般不走 PHP-FPM
因为静态资源不需要 PHP 解释执行。
如果图片、CSS、JS 也都打到 PHP-FPM,会浪费 worker。
正确分工通常是:
- 静态资源:Nginx 直接处理
- 动态 PHP:交给 PHP-FPM
这也是为什么 Nginx + PHP-FPM 这套组合能比较高效。
十三、项目里怎么讲更像你做过真实系统
你可以这样说:
我对 PHP-FPM 的理解不只是“它是 PHP 进程池”。更重要的是,我会把它放回真实请求链路里看:Nginx 负责接入和静态资源,动态请求通过 FastCGI 转给 PHP-FPM,PHP-FPM 再把请求交给 worker 执行。线上如果 FPM 打满,我会先看 worker 是否耗尽、slowlog 卡在哪一层、listen queue 有没有堆积,再决定是优化慢 SQL、处理外部依赖超时,还是扩进程池。
这就把“原理”和“项目经验”连起来了。
十四、30 秒版怎么答
FastCGI 是 Web Server 和外部程序通信的一种协议,解决的是 CGI 每个请求都临时起进程的性能问题。PHP-FPM 是 PHP 的 FastCGI 进程管理器,负责维护一组常驻的 PHP worker。Nginx 收到动态请求后,会通过 FastCGI 把请求转给 PHP-FPM,再由空闲 worker 执行脚本并返回结果。
十五、1 分钟版怎么答
我会把 CGI、FastCGI 和 PHP-FPM 分开讲。CGI 是早期动态请求模型,每个请求都起一个外部进程,开销很大;FastCGI 是它的改良版,通过常驻进程和协议通信避免反复起进程;PHP-FPM 则是 PHP 在 FastCGI 模式下的进程管理器,负责维护 master 和一组 worker。Nginx 负责连接接入、静态资源和反向代理,动态请求通过 FastCGI 协议交给 PHP-FPM,再由 worker 执行 PHP 脚本。线上如果 PHP-FPM 打满,我会先看 slowlog、worker 数、listen queue 和下游依赖,而不是只会调大 max_children。
十六、3 分钟版怎么答
我理解这题的关键,是把 CGI、FastCGI 和 PHP-FPM 的边界讲清楚。CGI 是早期 Web Server 调外部程序的方式,但它的问题是每个请求都要临时创建进程,高并发下成本太高。FastCGI 本质上是 CGI 的常驻进程化版本,它通过协议让 Web Server 和常驻进程通信,避免重复 fork/exec。
PHP-FPM 不是协议本身,而是 PHP 的 FastCGI 进程管理器。它内部通常有 master 和 worker 两类进程,master 负责监听 socket、拉起和回收 worker、平滑重载配置,worker 负责真正执行 PHP 脚本,而且一个 worker 同一时刻通常只处理一个请求。
所以实际链路通常是:客户端把 HTTP 请求打到 Nginx,Nginx 判断静态资源还是动态请求;静态资源直接由 Nginx 处理,动态请求通过 FastCGI 转发给 PHP-FPM;PHP-FPM 从进程池里选择空闲 worker 执行脚本,执行完成后再把结果返回给 Nginx。
线上排查时,我更关注的是 worker 是否耗尽、slowlog 卡在 SQL 还是外部依赖、listen queue 有没有堆积。因为 FPM 打满通常不是单纯参数小,而是请求处理速度跟不上请求到达速度。调大 max_children 只是手段,真正要看是不是慢 SQL、缓存失效、第三方接口超时或者突发流量带来的问题。
十七、这题最容易答错的地方
1. 把 FastCGI 和 PHP-FPM 当成一个东西
更准确的说法应该是:
- FastCGI 是协议
- PHP-FPM 是 FastCGI 进程管理器
2. 只会背 Nginx + PHP-FPM
面试官更想听的是:
- 为什么需要它们分工
- 请求是怎么流转的
- 为什么会打满
3. 遇到问题只会说“调大参数”
真正更好的说法是:
- 先分析慢在哪里
- 再决定扩容还是优化
十八、你可以记住的最终一句话
FastCGI 解决的是 CGI 每次都起进程的问题,PHP-FPM 解决的是 PHP 在 FastCGI 模式下怎么稳定地管理一组常驻 worker,Nginx 则负责接入、转发和静态资源处理。