这几天维护一台 2 核 2G 的轻量云服务器,上面挂着两个 WordPress 和一个自建工具站。某天晚上收到监控告警,CPU 使用率直接拉到 100%,站点开始断断续续报 502 Bad Gateway。
SSH 登上去用 top 一看,四五个 php-fpm: pool www 进程各自霸占了 30% 到 50% 的 CPU。这篇文章把这次排查步骤、关键参数的设置依据整理下来,免得以后遇到类似问题又要重头翻笔记。
1. 紧急处理与即时定位
遇到这种情况,最先要做的是让站点恢复响应,随后立刻找引发跑满的请求。
如果面板此时卡死打不开,可以直接在终端平滑重载 PHP 服务:
bashsystemctl 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 核 1G | 10 | 2 | 2 | 5 | 500 | 1024 MB |
| 2 核 2G | 20 | 4 | 4 | 10 | 1020 | 2048 MB |
| 2 核 4G | 40 | 8 | 6 | 20 | 2048 | 2048 MB |
这里重点解释一下 max_requests。很多默认配置把这个值设成 0(代表进程永不销毁),但由于不少开源程序和第三方插件存在隐性内存泄漏,长时间运行后单个 PHP 进程会吃掉上百兆内存。将其限制在 500~1020 之间,进程处理完指定请求量后就会自动释放并重建,对稳定小内存服务器非常有效。
3. 开启慢日志抓取耗时脚本
如果调整了参数,某个进程依然偶尔吃满单核 CPU,通常是特定代码逻辑有问题(比如 WordPress 的某个插件在做远程 API 请求,或者查询了未经索引的大数据表)。
此时最有效的排查手段是开启 PHP 慢查询日志(Slow Log)。在宝塔的 PHP 配置文件中找到或添加:
inirequest_slowlog_timeout = 3s slowlog = /www/server/php/74/var/log/slow.log
修改后保存并重载 PHP。当一个 PHP 请求执行超过 3 秒,系统就会将具体的调用栈(精确到 PHP 文件、函数名和行号)记录到 slow.log 中。
排查时直接查看该文件:
bashtail -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 消耗。