PHP 站点慢,八成问题在 PHP-FPM:进程数不够导致排队、进程数太多导致内存耗尽、没开 OPcache 导致每次都重新编译脚本。
这篇讲 PHP-FPM 的安装、进程模型、参数计算方法和调优思路。
PHP 调优后低配服务器也能跑得动。财富云计算 提供多种规格云服务器;内网服务、开发测试可选 NAT 型(无独立公网 IP,价格比带独立 IP 机型省一半以上)。
一、安装 PHP-FPM
Debian / Ubuntu
apt update
apt install php-fpm php-mysql php-gd php-curl php-mbstring php-xml php-zip php-opcache -y
php -v
systemctl enable --now php8.2-fpm # 版本号按实际CentOS / Rocky
yum install epel-release -y
yum install https://rpms.remirepo.net/enterprise/remi-release-8.rpm -y
yum module enable php:8.2 -y
yum install php php-fpm php-mysqlnd php-gd php-curl php-mbstring php-xml php-zip php-opcache -y
systemctl enable --now php-fpm关键路径
/etc/php/8.2/fpm/php.ini # PHP 主配置
/etc/php/8.2/fpm/pool.d/www.conf # 进程池配置(调优重点)
/run/php/php8.2-fpm.sock # Unix socket
/var/log/php8.2-fpm.log # 日志Debian 系用 socket,CentOS 默认可能用 127.0.0.1:9000。
二、Nginx 对接 PHP-FPM
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 超时设置
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
# 缓冲
fastcgi_buffering on;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
}socket vs TCP:
| 方式 | 优点 | 缺点 |
|---|---|---|
| Unix socket | 略快,无网络开销 | 只能本机 |
| TCP 127.0.0.1:9000 | 可跨机器、容器 | 略慢 |
单机推荐 socket;PHP 在另一台机器或 Docker 里则用 TCP。
验证:
echo "<?php phpinfo(); ?>" > /var/www/html/info.php
curl -I http://localhost/info.php
# 用完记得删:rm /var/www/html/info.php三、进程模型:三种模式
www.conf 里的 pm 参数:
1)static(静态)
pm = static
pm.max_children = 10固定保持 10 个进程,不增不减。
- 优点:无进程创建开销,响应最快、最稳定
- 缺点:内存占用固定(不管有没有请求)
- 适合:内存充足、流量稳定、追求性能的生产环境
2)dynamic(动态,默认)
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5按需增减进程,空闲时回收。
- 优点:省内存
- 缺点:流量突增时要现创建进程,有开销
- 适合:大多数场景
3)ondemand(按需)
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s有请求才创建进程,空闲 10 秒后杀掉。
- 优点:最省内存
- 缺点:第一个请求有明显延迟
- 适合:内存极小、访问稀疏的场景(如后台管理)
推荐:内存够就 static;一般情况 dynamic。
四、max_children 怎么算(最关键)
公式:
pm.max_children ≈ (可用内存 - 系统和其他服务占用) / 单个 PHP 进程平均占用获取单个 PHP 进程的内存占用:
# 看 RSS 列(单位 KB)
ps -o pid,rss,cmd -C php-fpm8.2
# 或者
ps aux | grep php-fpm | awk '{print $6}' | sort -n | tail -5假设:
- 服务器 2GB 内存
- 系统 + Nginx 占用 400MB
- MySQL 占用 500MB
- 单个 PHP 进程约 35MB
可用给 PHP = 2048 - 400 - 500 = 1148 MB
max_children = 1148 / 35 ≈ 32(保守取 20~25)一定要留余量,不然高峰期会 OOM。
快速参考表
| 服务器内存 | 场景 | max_children |
|---|---|---|
| 1GB | PHP + MySQL 同机 | 5~8 |
| 2GB | PHP + MySQL 同机 | 15~20 |
| 2GB | PHP 独立(MySQL 另机) | 30~40 |
| 4GB | PHP + MySQL 同机 | 40~50 |
| 4GB | PHP 独立 | 80~100 |
| 8GB | PHP 独立 | 150~200 |
验证是否够用——开启状态页:
; www.conf
pm.status_path = /phpfpm-statuslocation = /phpfpm-status {
access_log off;
allow 127.0.0.1;
deny all;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}curl http://127.0.0.1/phpfpm-status输出:
pool: www
process manager: dynamic
start time: 13/Oct/2026
accepted conn: 15420
listen queue: 0 ← 大于 0 说明有请求在排队
max listen queue: 12
listen queue len: 0
idle processes: 3
active processes: 7
total processes: 10
max active processes: 10 ← 经常打满说明进程不够
max children reached: 5 ← 大于 0 说明进程数不够,请求被拒
slow requests: 23关键指标:
| 指标 | 异常含义 |
|---|---|
listen queue > 0 | 请求在排队,进程不够或后端慢 |
max children reached > 0 | 进程数上限被打满,必须调大 |
slow requests > 0 | 有慢请求,要开慢日志查 |
五、其他重要参数
; www.conf
; 每个进程处理多少请求后重启(防内存泄漏累积)
pm.max_requests = 500
; 请求超时(超过就杀掉)
request_terminate_timeout = 60s
; 慢日志(强烈建议开)
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 2s
; 限制单个脚本内存
php_admin_value[memory_limit] = 128M
; 状态页
pm.status_path = /phpfpm-statuspm.max_requests 的作用:PHP 程序可能有轻微内存泄漏,进程跑久了内存会涨。设成 500 表示处理 500 个请求后自动重启该进程,释放内存。设为 0 表示不重启。
慢日志是排查性能问题的利器:
mkdir -p /var/log/php-fpm
systemctl restart php8.2-fpm
tail -f /var/log/php-fpm/slow.log它会打印出具体哪个文件的哪一行慢:
[13-Oct-2026 02:50:39] [pool www] pid 1234
script_filename = /var/www/html/index.php
[0x00007f] mysqli_query() /var/www/html/model/User.php:42六、OPcache:性能提升数倍
没有 OPcache 的 PHP:每个请求都要读取 PHP 文件 → 编译成字节码 → 执行。编译这一步占了大头。
有 OPcache:编译结果缓存在内存,后续请求直接执行字节码。
php -m | grep -i opcache # 检查是否安装
apt install php-opcache -y配置:
nano /etc/php/8.2/fpm/conf.d/10-opcache.inizend_extension=opcache.so
opcache.enable=1
opcache.memory_consumption=128 # 缓存内存,MB
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000 # 最多缓存多少个文件
opcache.revalidate_freq=2 # 检查文件更新的间隔(秒)
opcache.validate_timestamps=1 # 生产可设 0(配合部署时手动清除)
opcache.save_comments=1
opcache.fast_shutdown=1
; 生产环境优化(改代码后需手动 reload 才生效)
; opcache.validate_timestamps=0systemctl restart php8.2-fpm
php -i | grep opcache查看 OPcache 使用情况:
可以用 opcache-gui 或简单脚本:
<?php
$status = opcache_get_status();
echo "命中率: " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%\n";
echo "已用内存: " . round($status['memory_usage']['used_memory']/1048576, 2) . " MB\n";
echo "缓存脚本数: " . $status['opcache_statistics']['num_cached_scripts'] . "\n";命中率应该在 99% 以上。内存不够会导致缓存被清,命中率下降,要调大 memory_consumption。
七、php.ini 调优
memory_limit = 128M # 单脚本内存上限
max_execution_time = 30 # 单脚本最长执行时间
upload_max_filesize = 20M
post_max_size = 22M # 要略大于 upload
max_input_vars = 3000
realpath_cache_size = 4096K # 路径缓存,IO 多有提升
realpath_cache_ttl = 600
; 生产环境关闭错误显示
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
expose_php = Off # 隐藏版本八、系统层面的配合
1)文件句柄
ulimit -n
# /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535systemd 服务里也要设:
[Service]
LimitNOFILE=655352)PHP-FPM 的 limit
; www.conf
rlimit_files = 655353)内核参数
# /etc/sysctl.conf
net.core.somaxconn = 65535 # 连接队列
net.ipv4.tcp_max_syn_backlog = 65535sysctl -pNginx 里也要配:
listen 80 backlog=65535;九、调优实战流程
# ① 先看有没有 OPcache
php -m | grep opcache
# ② 看进程内存占用
ps -o pid,rss,cmd -C php-fpm8.2 | head
# ③ 算 max_children,改配置
# ④ 开状态页,观察
curl http://127.0.0.1/phpfpm-status
# ⑤ 开慢日志,找慢代码
tail -f /var/log/php-fpm/slow.log
# ⑥ 压测验证
ab -n 1000 -c 50 http://example.com/十、压测方法
# 安装 ab(Apache Bench)
apt install apache2-utils -y
# 1000 个请求,50 并发
ab -n 1000 -c 50 http://example.com/
# 带 Keep-Alive
ab -n 1000 -c 50 -k http://example.com/输出关键指标:
Requests per second: 245.32 [#/sec] ← 每秒处理请求数(QPS)
Time per request: 203.815 [ms] ← 平均每个请求耗时
Time per request: 4.076 [ms] (across all concurrent requests)
Failed requests: 0 ← 失败数必须为 0Failed requests 大于 0 通常就是 max_children 不够。
更专业的压测工具:wrk、JMeter、k6。
# wrk
wrk -t4 -c100 -d30s http://example.com/十一、常见问题
| 现象 | 原因 | 解决 |
|---|---|---|
| 502 Bad Gateway | PHP-FPM 没启动 / socket 路径错 / 进程全挂 | systemctl status、ls /run/php/ |
| 504 Gateway Timeout | 脚本执行超时 | 调 request_terminate_timeout 和 Nginx 的 fastcgi_read_timeout |
| 网站时快时慢 | 进程不够,请求排队 | 调大 max_children |
| 内存持续上涨 | 内存泄漏 | 设 pm.max_requests,或修代码 |
| 改了代码不生效 | OPcache 缓存 | systemctl reload php-fpm,或设 validate_timestamps=0 后手动清 |
| 上传文件失败 | upload_max_filesize / post_max_size / Nginx client_max_body_size | 三处都要够大 |
server reached pm.max_children | 进程数上限 | 调大,或查慢请求 |
502 且日志显示 connect() failed | socket 权限 | listen.owner/listen.group 配成 nginx 用户 |
十二、推荐配置模板
2 核 4G,PHP + MySQL 同机:
[www]
user = www-data
group = www-data
listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 12
pm.max_requests = 500
request_terminate_timeout = 60s
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 2s
pm.status_path = /phpfpm-status
rlimit_files = 65535
php_admin_value[memory_limit] = 128M1 核 1G,小博客:
pm = dynamic
pm.max_children = 8
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 300PHP 站点对内存比较敏感,配置不要太省。财富云计算 的云服务器支持按需升级内存,建议先用低配试跑,通过 phpfpm-status 观察后再决定是否升级。内网服务、测试环境可选 NAT 型(无独立公网 IP,价格比带独立 IP 机型省一半以上)。相关阅读:
- 《网站打开慢的排查流程》
- 《Nginx 安装与配置入门》
- 《用云服务器搭建 Typecho 博客》
延伸阅读
- 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
- 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
- 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
- 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
- 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
- RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
- 短链接服务搭建:Shlink 自托管,链接数据自己掌握
- 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道

[...]}注意 PATH_INFO:PHP-FPM 要开 cgi.fix_pathinfo=1,且 location ~ .php 段要带 fastcgi_param PATH_INFO。安全加固见PHP-FPM 安装与性能调优。4.4 单页应用(Vue/React)location / {[...]
2026-10-15 回复
[...]curl -o /dev/null -s -w "cached TTFB: %{time_starttransfer}s\n" https://你的域名TTFB判读<200ms优秀200-500ms正常(动态站)500ms-1s慢,查服务端>1s有问题:DB 慢/无缓存/机器过载服务端慢的排查:PHP 慢日志、MySQL 慢查询(见MySQL 慢查询优化)、无 OP[...]
2026-10-15 回复
[...]netsh advfirewall firewall add rule name="GameRange" dir=in action=allow protocol=UDP localport=26901-26903完整的 Windows 环境准备(远程桌面连接、运行库安装、SteamCMD 用法、开机自启、8 个常见坑)见:《Windows 云服务器开服通用前置教程》→ htt[...]
2026-10-18 回复
[...]└─ 联系我们 ← 电话、地址、表单、地图文案的常见错误:满屏"引领行业、卓越品质"这种空话。客户只关心"你能解决我什么问题、多少钱、靠不靠谱"。五、性能与安全:上线前 checklist性能(官网打开超过 3 秒,一半访客流失):开页面缓存,动态页面静态化,见PHP-FPM 安装与性能调优图片压缩 + WebP,方法论见网站图片与静态资源优化上 CDN,静态资源走 CDN,见CDN 加速配置[...]
2026-10-18 回复
[...]# 然后:建库建用户 → 传代码 → 写 Nginx server 块 → 配 PHP-FPM pool性能调优见PHP-FPM 安装与性能调优,Nginx 配置见Nginx 安装与配置入门。代价:每个环节都要自己排障,证书、计划任务、日志切割全手动。七、各路线资源占用实测参考路线基础占用2G 机器评价4G 机器评价LNMP 手动(单站)300–500M舒服奢侈宝塔 + LNMP 单站1–1.5G[...]
2026-10-18 回复