FastCGI 是通信协议,PHP-FPM 是其官方实现的进程管理器;php-cgi 仅为简易 CGI 工具,无进程管理能力;PHP-FPM 支持 static/dynamic/ondemand 三种子进程管理模式,需依场景选配。

FastCGI 是协议,PHP-FPM 是实现它的进程管理器
很多人一上来就混淆概念:FastCGI 不是某个可执行文件,而是一套通信规范(类似 HTTP),定义了 Web 服务器如何把请求数据打包发给后端程序、后端又怎么按格式返回响应。PHP-FPM 则是 PHP 官方提供的、严格遵循 FastCGI 协议的“服务端程序”——它监听 socket 或 TCP 端口,接收 Nginx/Apache 转发来的请求,调度 PHP-CGI 进程干活,并回收结果。
常见错误现象:connect() to unix:/run/php/php8.2-fpm.sock failed (2: No such file or directory),本质不是 PHP 没装,而是 php-fpm 服务根本没启动,或者 sock 文件路径跟 Nginx 配置里的 fastcgi_pass 不一致。
-
php-cgi是 PHP 自带的简易 FastCGI 实现,但无进程管理、不支持平滑重启、改了php.ini必须 kill 再 start -
php-fpm内置了 master 进程 + worker 进程模型,能 reload 配置、动态伸缩子进程、记录慢日志、限制单个请求内存/时间 - 你用
systemctl start php8.2-fpm启的,其实是php-fpm;Nginx 的fastcgi_pass指向的,也是它暴露的接口
三种 pm 运行模式怎么选:static / dynamic / ondemand
PHP-FPM 的核心性能开关在 /etc/php/8.2/fpm/pool.d/www.conf 里的 pm 配置项,它决定 PHP 子进程怎么生、怎么活、怎么死。
使用场景差异极大:小 VPS 跑个人博客和 16 核机器跑电商主站,pm=ondemand 和 pm=static 效果可能完全相反。
立即学习“PHP免费学习笔记(深入)”;
-
pm = static:固定数量子进程(如pm.max_children = 50),适合高并发、请求均匀的场景;缺点是空闲时也占满内存 -
pm = dynamic:默认模式,按负载自动伸缩(pm.start_servers、pm.min_spare_servers、pm.max_spare_servers共同控制);平衡内存与响应速度,大多数中型项目首选 -
pm = ondemand:空闲时干掉所有子进程,请求来了再 fork;省内存但首次响应慢,且频繁 fork 可能压垮低配机器;只推荐内存极度紧张(
为什么不能直接用 php-cgi 替代 php-fpm?
有人图省事,在 Nginx 里写 fastcgi_pass 127.0.0.1:9000,然后手动运行 php-cgi -b 127.0.0.1:9000 ——短期能跑,长期必出问题。
典型故障:502 Bad Gateway 随机出现,查日志发现 recv() failed (104: Connection reset by peer);或某次部署后 PHP 响应全变空白,但 php-cgi -v 显示正常。
-
php-cgi没有 master 进程守护,子进程崩溃后不会自动拉起,Nginx 就连不上了 - 修改
php.ini后必须手动killall php-cgi && php-cgi -b ...,期间服务中断;而php-fpm支持systemctl reload php8.2-fpm平滑生效 -
php-cgi不支持slowlog、pm.status_path、access.log等运维关键功能,排障基本靠猜
Nginx + PHP-FPM 通信失败的三个高频配置坑
90% 的 “PHP 不执行”、“502”、“空白页” 问题,根子不在 PHP 代码,而在 Nginx 和 PHP-FPM 的握手环节没对上。
最容易被忽略的是权限和上下文隔离:Nginx 工作进程用户(如 www-data)必须能读取 PHP-FPM 的 socket 文件,且两者 listen.owner/listen.group 设置要匹配。
- socket 路径不一致:Nginx 的
fastcgi_pass unix:/run/php/php8.2-fpm.sock要和 PHP-FPM 的listen = /run/php/php8.2-fpm.sock完全一致 - 权限不对:若 PHP-FPM 的
listen.owner = www-data但listen.mode = 0660,而 Nginx 进程属于www-data组,就 OK;若 mode 是0600,Nginx 就读不了 - SELinux 或 AppArmor 开启时,即使路径权限都对,也会静默拒绝访问;临时验证可先
setenforce 0或检查ausearch -m avc -ts recent
pm 模式调优和 socket 权限这两块,比写 PHP 代码还容易卡住人。尤其换了新系统(比如从 Ubuntu 换到 Rocky Linux),默认 SELinux 状态、用户组策略、socket 目录归属全变了,照搬旧配置大概率挂。











