先确认是否php-fpm进程池耗尽:检查active processes是否持续接近max_children、max_children_reached是否每秒增长;若idle processes常年5–10个但cpu仍打满,才是真cpu密集型问题。

看 PHP-FPM 进程池状态,先排除配置瓶颈
CPU 打满不等于代码有问题,很可能是 PHP-FPM 进程池被“等”满了。关键指标不是 CPU 百分比,而是 max_children_reached 是否持续增长。
- 开启 PHP-FPM status 页面(
pm.status_path = /status,配合 Nginx location 转发),用 curl 查:curl http://127.0.0.1/status?full - 重点观察:
active processes接近或等于max_children,且max_children_reached每秒都在涨 → 进程池不够,属于配置问题 - 如果
idle processes常年有 5–10 个,但 CPU 仍打满 → 真正的 CPU 密集型任务在运行,才该怀疑代码
用 strace 抓住正在忙的 PHP 进程,看它到底在干啥
别猜,直接看系统调用。一个长期占 CPU 的进程,要么在死循环,要么在反复做某件事(比如轮询、加密、正则回溯)。
- 先用
htop或ps aux --sort=-pcpu | head -10找出高 CPU 的php-fpmworker 进程 PID - 对准那个 PID 执行:
sudo strace -cp 17487(运行 5 秒后自动退出),看输出里占比最高的系统调用是什么 - 常见线索:
poll/select高 → 在等 I/O(可能是数据库/Redis 超时未设);clock_gettime+brk高 → 内存频繁分配,可能有大数组或未释放资源;全是nanosleep→ 实际是空转,大概率死循环
检查 error_log 和 slow log,确认有没有隐性阻塞
很多 CPU 打满,表面是计算,实则是“卡在等待”——而这种等待会让 PHP 进程持续占用 CPU 时间片,直到超时。
- 打开 PHP-FPM 的
slowlog(slowlog = /var/log/php-fpm-slow.log,request_slowlog_timeout = 2s),压测时看有没有记录 - 查
error_log里是否反复出现:PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away或RedisException: read error on connection—— 这类错误常触发重试逻辑,形成隐式循环 - 检查代码里是否有没设超时的
file_get_contents()、curl_exec()、stream_socket_client(),它们默认会无限等
对比本地和线上,盯住 opcache 和 realpath_cache
PHP 7.4 下,opcache.validate_timestamps=0 + 未重载缓存,会导致旧代码一直跑;而 realpath_cache_size 太小,会在大量 require 时反复 stat 文件,吃光 CPU。
- 线上执行
php -i | grep -E "(opcache|realpath)",对比本地输出 - 重点关注:
opcache.enable(必须 On)、opcache.validate_timestamps(线上应为 0)、realpath_cache_size(建议 ≥ 4M)、realpath_cache_ttl(建议 ≥ 3600) - 如果线上
realpath_cache_size是默认的 16K,又用了 Composer 自动加载 + 深层命名空间路径,每请求上百次stat()就够把 CPU 拉到 80%+
blackfire 或 xhprof 抓函数调用栈,而不是盯着 top 看数字。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











