最近在维护一台 2核2G 的轻量云服务器,上面挂着两个 WordPress 博客和一个用 Laravel 写的小接口。前阵子偶尔会收到云监控发来的 CPU 100% 告警,打开前台偶尔还会跳 502 Bad Gateway。连上终端敲了下 top,发现排在前面的清一色全是 php-fpm: pool www 进程。
顺手把排查过程、核心参数的调整基准记录下来,方便以后自己重装系统时查阅,也给遇到同样情况的朋友一个参考。
1. 紧急处置与临时恢复
当线上站点已经完全打不开,CPU 持续跑满时,最快的应急操作是先把现有的僵死进程释放掉:
- 在终端直接执行
systemctl restart php-fpm-xx(xx 为具体版本号,如 74、81),或者在宝塔面板的软件商店找到对应的 PHP 版本点击“重启”。 - 检查磁盘剩余空间与 Swap 分区。内存不足时如果没有配置 Swap,Linux 内核在尝试分配内存失败后极易引发进程剧烈抖动甚至触发 OOM 机制强行杀进程。
但这只能救急,很多时候重启几分钟后,只要访客流量稍微上来或者爬虫一扫,CPU 又会瞬间被吃满。
2. 核心性能参数调整参考
很多人在宝塔里调整 PHP-FPM 时,会直接选用预设的“并发方案”(如直接选 100 并发或 300 并发),这在小内存机器上往往是崩溃的根源。
一个跑着复杂 CMS 的 PHP-FPM 子进程,在处理动态请求时平均要消耗 30MB 到 60MB 内存。如果一台 2G 内存的机器开了 80 个进程,光 PHP 就可能吃掉 3G 以上内存,系统被迫疯狂使用虚拟内存换页,导致 CPU 负载飙升。以下是针对小机器实测相对平稳的参数基准:
| 服务器配置 | 运行模式 (pm) | max_children | start_servers | min_spare | max_spare | max_requests | 建议 Swap 大小 |
|---|---|---|---|---|---|---|---|
| 1核 1G 内存 | dynamic | 10 | 2 | 2 | 5 | 1024 | 1G - 2G |
| 2核 2G 内存 | dynamic | 20 | 3 | 3 | 10 | 1024 | 2G |
| 2核 4G 内存 | dynamic | 40 | 5 | 5 | 20 | 2048 | 2G - 4G |
这里有两项关键设置:
pm = dynamic:动态管理进程数,空闲时释放内存,避免常驻进程吃光资源。pm.max_requests = 1024:指定每个子进程处理完 1024 个请求后自动重启。PHP 很多第三方扩展存在微小的内存泄漏问题,限制最大请求数能有效防止单个进程随时间推移越变越大。
3. 定位具体执行慢的脚本
如果调整了并发参数,CPU 依然经常性被打满,问题大概率出在某个具体的 PHP 脚本卡住了进程。
开启 PHP 慢日志(Slow Log)
打开宝塔对应的 PHP 设置面板,在配置文件中找到慢日志配置项,将超时门槛设为 3 到 5 秒:inirequest_slowlog_timeout = 3 slowlog = var/log/slow.log
保存并重载 PHP 配置。当 CPU 再次飙高时,直接查看 /www/server/php/版本号/var/log/slow.log。慢日志会精确打印出卡住的 PHP 文件路径甚至具体到第几行代码。常见的元凶包括:
- 某个 WordPress 插件正在向国外未翻墙的 API 发送请求,超时等待几十秒;
- 数据库某张表没有加索引,执行了全表扫描的大查询;
- 循环写入大文件或处理未压缩的高清图片。
排查外部异常流量
如果慢日志里全是常规的页面脚本,说明是单位时间内的请求频率远超服务器承载力。可以在终端统计 Nginx 的访问日志:bash# 统计访问频次最高的前 10 个 IP awk '{print $1}' /www/wwwlogs/你的域名.log | sort | uniq -c | sort -nr | head -n 10
通常会抓到某些海外爬虫在频繁抓取搜索接口或疯狂刷后台登录页。如果不想手工去切日志分析,也可以开启宝塔自带的“网站监控报表”插件或 Nginx 官方 WAF 模块,把恶意 IP 封禁或对动态页面做频率限制。
4. 为什么改完参数后还是会被打崩?
动态脚本的处理能力是有物理上限的。2核服务器跑 PHP,极限并发承载通常也就几十个纯动态请求。要彻底让 CPU 降下来,核心思路是“尽可能不让请求走到 PHP”:
- 开启 OPcache:在宝塔 PHP 安装扩展界面开启 OPcache。它会把编译后的 PHP 字节码缓存在内存中,避免每次请求重复解析编译,能立竿见影降低 20%~40% 的 CPU 开销。
- 使用页面级静态缓存:如果是博客或内容类站点,务必配置 Redis Object Cache 或利用 Nginx 的
fastcgi_cache模块把未登录用户的访问转为静态内容响应。大部分常规访客无需唤醒 PHP-FPM 进程,CPU 就会稳定在极低的水平。