宝塔面板下 PHP-FPM 进程 CPU 飙升排查与调优记录

核心导读:记录一次轻量服务器 PHP-FPM 偶发性跑满 CPU 的排查过程,梳理了进程池关键参数的配置逻辑与慢日志抓取方法,附上小内存主机的调优参考。

这几天维护一台 2 核 2G 的轻量云服务器,上面挂着两个 WordPress 和一个自建工具站。某天晚上收到监控告警,CPU 使用率直接拉到 100%,站点开始断断续续报 502 Bad Gateway。

SSH 登上去用 top 一看,四五个 php-fpm: pool www 进程各自霸占了 30% 到 50% 的 CPU。这篇文章把这次排查步骤、关键参数的设置依据整理下来,免得以后遇到类似问题又要重头翻笔记。

1. 紧急处理与即时定位

遇到这种情况,最先要做的是让站点恢复响应,随后立刻找引发跑满的请求。

如果面板此时卡死打不开,可以直接在终端平滑重载 PHP 服务:

bash
systemctl reload php-fpm-74 # 这里的版本号根据自己的实际情况替换

但这只能救急几分钟。想知道究竟是哪个 PHP 进程在吃资源,可以通过以下命令打印当前活跃进程正在处理的脚本:

bash
# 查看具体高占用的 php-fpm 进程 PID top -c -u www # 查看对应进程打开的文件或系统调用 strace -p <PID> -s 1024 -f

如果终端刷出一堆等待外部 curl 响应、或者某个主题文件里死循环读取数据库的代码,就能直接抓出元凶。

2. 进程池关键参数调优

宝塔默认安装 PHP 后的“性能调整”参数偏通用,但对 1G~2G 的轻量小主机来说,往往不够合理。很多时候 CPU 飙高并不是算力不够,而是并发进程开得太多,导致物理内存耗尽,系统频繁走 Swap 交换,最终把 CPU 全部卡死在 I/O 等待上。

在宝塔面板的【PHP 管理】->【性能调整】中,模式建议选择 dynamic(动态),关键参数可以按机器配置做如下调整:

机器内存max_children (最大进程)start_servers (起始)min_spare (最小空闲)max_spare (最大空闲)max_requests (请求数)建议 Swap 大小
1 核 1G102255001024 MB
2 核 2G20441010202048 MB
2 核 4G40862020482048 MB

这里重点解释一下 max_requests。很多默认配置把这个值设成 0(代表进程永不销毁),但由于不少开源程序和第三方插件存在隐性内存泄漏,长时间运行后单个 PHP 进程会吃掉上百兆内存。将其限制在 500~1020 之间,进程处理完指定请求量后就会自动释放并重建,对稳定小内存服务器非常有效。

3. 开启慢日志抓取耗时脚本

如果调整了参数,某个进程依然偶尔吃满单核 CPU,通常是特定代码逻辑有问题(比如 WordPress 的某个插件在做远程 API 请求,或者查询了未经索引的大数据表)。

此时最有效的排查手段是开启 PHP 慢查询日志(Slow Log)。在宝塔的 PHP 配置文件中找到或添加:

ini
request_slowlog_timeout = 3s slowlog = /www/server/php/74/var/log/slow.log

修改后保存并重载 PHP。当一个 PHP 请求执行超过 3 秒,系统就会将具体的调用栈(精确到 PHP 文件、函数名和行号)记录到 slow.log 中。

排查时直接查看该文件:

bash
tail -n 50 /www/server/php/74/var/log/slow.log

顺着日志里定位的文件去停用有问题的插件或重写慢 SQL,往往能彻底解决偶发性 CPU 飙升。

4. 为什么调完参数还是偶尔会被打满?

如果代码本身没有大问题,配置也按内存压下去了,但每天某个时间段依然 CPU 报警,大概率是碰到了爬虫或批量扫描。

很多国外搜索引擎(如 AhrefsBot、SemrushBot)或者漏洞扫描器会无视频率,短时间内高并发请求动态页面。此时如果每个请求都穿透到 PHP-FPM 处理,进程池很快就会排满。

建议排查路径如下:

  • 查看对应站点的 Nginx 访问日志,检查是否有某个 IP 或特定 User-Agent 在高频刷 /search//?s= 等动态 URL。
  • 如果不想手动写 iptables 或在 Nginx 里写正则,可以开启宝塔面板的网站监控报表插件看一眼请求分布,或者使用面板自带的 Nginx 防火墙插件设置单 IP 并发频率限制。
  • 对于展示型博客,尽量配合 Nginx 的 FastCGI Cache 或 WP Super Cache 等插件,将页面静态化落盘。这样爬虫再怎么扫,请求都由 Nginx 直接吐出静态文件,PHP 进程基本不会产生额外的 CPU 消耗。

常见问题与解答 (FAQ)

Q 改完 PHP 的性能参数后,点平滑重载管用还是必须重启?

修改 pm 参数和慢日志通常点“重载配置”(reload)就能生效;但如果调整了 max_children 且当前并发较高,建议在访问低谷期直接点击“重启”,能更快清空旧的僵尸进程。

Q 小内存机器平时负载不高,有必要单独分配 Swap 交换分区吗?

很有必要。Swap 在并发突发时能充当缓冲气囊,避免 Linux 内核因内存不足(OOM)直接强制杀掉 MySQL 或 PHP 进程,配合合适的 swappiness 参数并不会影响磁盘性能。

返回运维知识库