13 10 月 2026

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
1GBPHP + MySQL 同机5~8
2GBPHP + MySQL 同机15~20
2GBPHP 独立(MySQL 另机)30~40
4GBPHP + MySQL 同机40~50
4GBPHP 独立80~100
8GBPHP 独立150~200

验证是否够用——开启状态页:

; www.conf
pm.status_path = /phpfpm-status
location = /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-status

pm.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.ini
zend_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=0
systemctl 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 65535

systemd 服务里也要设:

[Service]
LimitNOFILE=65535

2)PHP-FPM 的 limit

; www.conf
rlimit_files = 65535

3)内核参数

# /etc/sysctl.conf
net.core.somaxconn = 65535        # 连接队列
net.ipv4.tcp_max_syn_backlog = 65535
sysctl -p

Nginx 里也要配:

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                   ← 失败数必须为 0

Failed requests 大于 0 通常就是 max_children 不够。

更专业的压测工具:wrk、JMeter、k6。

# wrk
wrk -t4 -c100 -d30s http://example.com/

十一、常见问题

现象原因解决
502 Bad GatewayPHP-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() failedsocket 权限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] = 128M

1 核 1G,小博客:

pm = dynamic
pm.max_children = 8
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 300

PHP 站点对内存比较敏感,配置不要太省。财富云计算 的云服务器支持按需升级内存,建议先用低配试跑,通过 phpfpm-status 观察后再决定是否升级。内网服务、测试环境可选 NAT 型(无独立公网 IP,价格比带独立 IP 机型省一半以上)。

相关阅读:

  • 《网站打开慢的排查流程》
  • 《Nginx 安装与配置入门》
  • 《用云服务器搭建 Typecho 博客》
延伸阅读
  1. 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
  2. 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
  3. 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
  4. 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
  5. 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
  6. RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
  7. 短链接服务搭建:Shlink 自托管,链接数据自己掌握
  8. 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道
更多阅读
  1. 上一篇:Linux 日志管理与 logrotate 配置:日志撑爆磁盘怎么办
  2. 下一篇:网站被 CC 攻击怎么办:识别、缓解、防御的完整流程
发表评论 5

取消回复