宝塔面板PHP-FPM进程占用CPU过高的排查与调优记录

核心导读:记录服务器上 PHP-FPM 偶尔把 CPU 和内存占满导致 502 报错的排查过程,包含进程分析、慢日志定位、不同内存规格的参数配置参考以及防击穿思路。

最近维护一台 2G 内存的轻量云服务器,时不时收到 CPU 负载超过 90% 的告警,打开站点直接报 502 Bad Gateway。登录宝塔后台一看,十几个 php-fpm 进程把 CPU 和内存几乎吃满。以前总以为是并发访问量上来了,仔细排查后发现,大多是几个耗时脚本阻塞加上爬虫集中抓取导致的。顺手把这次排查步骤和目前验证过比较平稳的配置参数记下来,方便备忘。

1. 临时恢复与现场排查

如果站点已经打不开,第一步先让服务恢复响应,再留存现场:

  1. 释放阻塞进程:在宝塔面板的【软件商店】进入对应 PHP 版本,点击“重载配置”或“重启”。如果命令行操作更顺手,直接执行 systemctl reload php-fpm-xx(xx 为对应版本号)。
  2. 确认资源消耗大户:终端执行 top 或 htop,按 P(按 CPU 排序)或 M(按内存排序)。如果列表中清一色是 php-fpm: pool www,且持续占用 80%-100% 的单核 CPU,说明请求被挂起在特定逻辑里未能释放。
  3. 查看当前并发池状态:在宝塔 PHP 配置中开启 status 页面,访问对应端点可以看到当前 active processes(活动进程数)和 listen queue(排队队列)。如果活动进程数一直等于最大子进程数,后续请求就会直接在 Nginx 处超时报错。

2. 关键参数设置参考

PHP-FPM 默认的并发参数往往偏宽松,小内存服务器直接套用默认值极易跑崩。单个 PHP-FPM 进程在 WordPress 或常规框架下通常会占用 30MB 到 60MB 内存,如果遇到上传处理或复杂查询,峰值可能达到 100MB 以上。

算好机器剩余可用内存,再反推子进程上限,是最稳妥的办法:

服务器配置建议 PHP 运行模式max_childrenstart_serversmin/max_spare_serversmax_requests建议 Swap 大小
1核 1Gondemand / dynamic8 - 1022 / 55001024 MB
2核 2Gdynamic20 - 3055 / 1510242048 MB
2核 4Gdynamic40 - 601010 / 2520482048 MB

几点参数细节说明:

  • pm.max_children:硬性决定最多同时处理多少个动态请求。不要盲目填大,设为 50 但内存只有 1G 时,一旦被刷,系统直接触发 OOM 杀进程。
  • pm.max_requests:每个子进程处理完指定数量的请求后自动重启。PHP 容易出现第三方扩展或代码层面的隐性内存泄露,将其设为 500 或 1024 能强制释放旧进程,极其管用。
  • 合理开启 Swap:低配服务器务必在 Linux 工具箱里配置 1G 到 2G 的 Swap 虚拟内存,当流量突发时可以作为缓冲区,避免服务直接闪退。

3. 查看日志定位具体原因

改完参数只是防止服务器物理卡死,真正导致 CPU 飙高的脚本依然需要找出来。

开启 PHP 慢日志(Slowlog)

这是定位问题最直接的手段。在 PHP 服务的【配置文件】中,找到并开启 slowlog:
ini
request_slowlog_timeout = 3s slowlog = /www/server/php/80/var/log/slow.log

设置当请求超过 3 秒时记录堆栈信息。重载 PHP 后,执行 tail -f /www/server/php/80/var/log/slow.log。
很多时候会发现慢日志里反复卡在某一个数据库查询函数、调用外部 API 超时(如微信接口、远程头像),或者某些插件的后台定时任务。

检查 Nginx 访问日志

慢脚本往往是被外部高频触发的。进入 /www/wwwlogs/,统计最近访问频率最高的 IP 和 URL:
bash
# 统计访问量前 10 的 IP awk '{print $1}' your_site.log | sort | uniq -c | sort -nr | head -n 10

如果发现某些来自非主流搜索引擎的爬虫(如 Bytespider、AhrefsBot)或者恶意扫描程序,以每秒几十次的速度轰炸搜索页、评论接口等动态接口,CPU 必定瞬时打满。

4. 为什么只调参数依然容易被打崩?

很多朋友改完配置后发现,虽然机器不报内存溢出了,但 CPU 还是经常 100%。单纯限制 max_children 只是把“崩服务器”变成了“排队超时”,根治问题还需要结合架构处理:

  1. 尽量减少动态请求直接下发到 PHP:对于内容类站点,页面缓存是解决 CPU 问题的杀手锏。静态文件交由 Nginx 直发,页面层面配合 Redis Cache 或 WP Super Cache 插件生成静态 HTML,95% 以上的访客就不会真正触发 PHP-FPM 进程。
  2. 拦截垃圾爬虫与高频扫号:通过 Nginx 配置文件直接针对恶意 User-Agent 返回 403,或者在 Nginx 层面开启 limit_req 模块限制单 IP 请求速率。如果手头有宝塔自带的 Nginx 免费防火墙或网站监控报表插件,也可以直接开启对应的防扫描与 UA 过滤规则,省去手工写正则的麻烦。
  3. 数据库慢查询优化:如果慢日志显示是 SQL 耗时过长,检查是否缺失索引,或者检查后台是否有全表扫描的复杂统计报表在频繁触发。

常见问题与解答 (FAQ)

Q 修改了 PHP-FPM 的参数后,必须重启 PHP 吗?

需要让配置生效,但不需要强制硬重启;在面板中点击“重载配置”即可平滑加载新参数,不会中断当前正在处理的请求。

Q 小内存机器开启 Swap 会不会拖慢磁盘 IO 导致更卡?

只要平时物理内存有富余,Swap 只充当突发峰值的兜底安全气囊;相比物理内存耗尽直接触发系统死机,合理的 Swap 对轻量站点的磁盘寿命和性能影响微乎其微。

返回运维知识库