最近在维护一台 2G 内存的轻量云服务器,上面挂了一个 WordPress 和两个轻量 API 服务。前两天监控突然告警,提示 CPU 连续十几分钟跑满 100%,站点也开始断断续续报 502 Bad Gateway。
SSH 连上去用 top 一看,四五个 php-fpm: pool www 进程直接把核心全占了。趁着这次排查,把处理步骤和目前跑得比较稳定的参数记下来,方便日后翻看。
1. 紧急处置与状态确认
CPU 跑满导致服务器卡死时,第一步先让服务恢复响应,然后再看现场:
- 在宝塔面板的【软件商店】里找到当前使用的 PHP 版本(比如 PHP 7.4 或 8.1),直接点击【重启】。这一步能快速干掉所有僵死的 Worker 子进程。
- 如果面板已经卡得进不去,直接在终端执行重启命令:
systemctl restart php-fpm-74(根据自己版本调整数字)。 - 恢复之后,在终端执行
top -c,按大写P让进程按 CPU 占用排序,观察重启后拉起的 PHP-FPM 进程数和资源消耗曲线。
2. 开启慢日志与访问日志定位问题
PHP-FPM 占用高通常只有两种原因:要么是某些 PHP 脚本执行超时、陷入死循环或在等慢查询;要么是遇到了恶意爬虫或并发请求轰炸。光靠猜没用,必须看日志。
开启 PHP 慢日志(Slow Log)
在宝塔面板打开 PHP 对应版本的配置,找到【服务】或者直接在配置文件中确认:
inirequest_slowlog_timeout = 3 slowlog = /www/server/php/74/var/log/slow.log
这里的 3 表示一个请求只要执行超过 3 秒,就会把完整的调用栈记录到 slow.log 中。修改后重载配置。一旦 CPU 再次飙高,直接查看这个日志:
bashtail -n 50 /www/server/php/74/var/log/slow.log
如果日志里反复出现某个插件、数据库查询函数或 curl_exec,那就是代码逻辑堵塞拖垮了整个 PHP 进程。
检查 Nginx 访问日志
如果慢日志里空空如也,那大概率是瞬时请求量过大。去查看 /www/wwwlogs/ 目录下站点的 access.log,看看是不是有特定 IP 在疯狂刷 wp-login.php、xmlrpc.php 或者某个没有做频率限制的搜索接口。
3. PHP-FPM 关键参数设置参考
宝塔默认安装 PHP 时,进程池模式一般设为 dynamic(动态)。默认分配的子进程数量对于 1G/2G 的小内存机器往往偏激进,一旦并发稍微上来,进程占满内存又抢占 CPU,系统就会开始卡死。
在 PHP 管理中的【性能调整】页面,建议结合服务器内存进行合理收缩:
| 服务器配置 | 运行模式 | max_children (最大子进程) | start_servers (起始) | min_spare (最小空闲) | max_spare (最大空闲) | max_requests (最大请求数) |
|---|---|---|---|---|---|---|
| 1核 1G | dynamic | 8 | 2 | 2 | 4 | 1024 |
| 2核 2G | dynamic | 20 | 4 | 4 | 10 | 1024 |
| 2核 4G | dynamic | 40 | 8 | 6 | 20 | 2048 |
几个核心参数的说明:
pm.max_children:允许创建的最大子进程数。一个常规的 WordPress 进程大概吃 30MB 到 60MB 内存。如果是 2G 机器,除去系统和 MySQL,留给 PHP 的大概也就 1G 左右,设 20 个左右是最安全的边界,宁可让后续请求排队,也不能让进程把物理内存打穿。pm.max_requests:每个子进程处理多少次请求后自动退出重启。这个非常关键,PHP 很多第三方扩展存在轻微的内存泄漏,设为1024可以强制周期性释放内存,避免进程长期常驻导致越跑越重。
4. 为什么调小参数后依然容易卡死?
很多朋友改完 max_children 发现 CPU 依然居高不下,这通常是因为没解决“请求源头”的问题:
- 没有开静态缓存:WordPress 等 CMS 如果每次请求都实打实穿透到 PHP 处理,单核机器扛不住 50 QPS。务必开启 Opcache 扩展,并配合 WP Super Cache 或 Redis 缓存,将不需要动态计算的页面直接走静态缓存返回。
- 恶意爬虫与扫描:如果访问日志里全是不明 User-Agent 在高频抓取,调小参数只会让队列堆积、网站更快报 502。这种情况下需要使用 Nginx 规则阻断异常 IP,或者在宝塔的 Nginx 防火墙插件中开启频次限制,把恶意流量挡在 Web 服务器层,不让其进入 PHP 解析阶段。