本文目录导读:

定位 PHP CPU 占用高的问题,通常需要结合系统工具、PHP 自身以及代码逻辑三个层面进行排查,以下是系统的定位步骤:
第一层:快速定位到具体进程
首先找出是哪个 PHP 进程导致的问题。
-
top / htop(实时查看)- 执行
top,按P(大写 P)按 CPU 降序排列。 - 确认消耗 CPU 的进程是
php-fpm、php-cli(脚本)还是httpd(模组方式)。 - 记录下高负载的 PID (进程ID)。
- 注意:对于
php-fpm,如果多个 worker 很高,那是并发问题;如果只有 1 个极高,那是单个请求有问题。
- 执行
-
strace(跟踪系统调用,看它在干什么)- 对有问题的 PID 执行:
strace -cp <PID>(统计系统调用耗时) - 或者实时跟踪:
strace -T -p <PID>(-T显示每个调用的耗时) - 观察点:
- 是否大量调用
read/write? -> 磁盘 I/O 瓶颈。 - 是否大量
connect/sendto? -> 网络请求 或 数据库 慢。 - 是否非常多
nanosleep? -> 代码里有睡眠、轮询或锁等待。
- 是否大量调用
- 对有问题的 PID 执行:
第二层:深入 PHP 内部
既然确认了是 PHP 问题,继续看它在运行什么代码。
-
检查
php-fpm慢日志 (最高效的方法)- 修改
php-fpm.conf或www.conf配置:; 启用慢日志 request_slowlog_timeout = 5 ; 脚本执行超过5秒就记录 slowlog = /var/log/php-fpm/www-slow.log request_terminate_timeout = 60 ; 最多允许60秒,超时杀死进程
- 分析:重启 PHP-FPM 后,查看
www-slow.log,它会告诉你哪个 PHP 文件、哪一行函数卡住了,这是最直接的定位方式。
- 修改
-
使用
pmap查看内存映射 (排查死循环或内存泄漏)pmap -x <PID> | sort -k 3 -rn | head -10- 如果发现大量
[anon]段,或内存异常大,可能存在循环分配或大数组操作。
-
gdb抓取调用栈 (终极手段,适合无慢日志环境)- 安装
gdb并确保 PHP 安装了 debug 符号包(或带--enable-debug编译)。 - 执行:
gdb -p <PID> - 在
(gdb)提示符下输入:set pagination off thread apply all bt - 这会打印所有线程的堆栈。寻找
execute_ex或zend_vm_execute调用链,看它卡在哪个函数上。
- 安装
第三层:分析与解决常见原因
定位到具体文件后,根据现象分析原因:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 数据库查询慢 | 慢日志中显示大量 mysql_query / PDO->query |
开启数据库慢查询日志 为查询添加索引 使用 EXPLAIN 分析SQL |
| 大量 file_get_contents / curl | 请求外部 API 或读取文件无限阻塞 | 设置 curl 超时时间(如 CURLOPT_TIMEOUT)使用异步并发或队列处理 |
| 无限循环 | for(;;) 或 while(true) |
在循环内增加 break 条件或计数限制 |
| 正则表达式回溯 | 使用了类似 的复杂正则匹配长字符串 | 使用 preg_match 的 PREG_UNMATCHED_AS_NULL 或限制匹配长度,避免灾难性回溯 |
| session 文件锁阻塞 | 高并发下 session_start() 锁等待 |
高并发场景改用 Redis/Memcached 存储 session |
| OpCache 未开启 | 每次请求重复解析、编译 PHP 文件 | 开启 OpCache,设置合适的 opcache.validate_timestamps |
| OOM (内存不足) 导致频繁交换 | 物理内存耗尽,系统频繁 swap,I/O 飙升导致 CPU 软中断 | 排查内存泄漏,或增加物理内存 |
第四层:短期应急与常态监控
- 应急重启:
systemctl restart php-fpm或kill -USR2 <master pid>(平滑重启,不中断请求),但只是临时缓解,问题还会复现。 - 建立监控:
- 使用
top或 Prometheus + Node Exporter 监控 CPU。 - 部署 Pinpoint / SkyWalking 等 APM 工具,直接看到每个请求的调用链耗时。
- 无论是
php-fpm还是apache mod_php,慢查询日志都是首选方案,务必优先配置。
- 使用
总结命令清单
# 1. 找出最消耗 CPU 的 PHP 进程
ps aux --sort=-%cpu | grep php | head -20
# 2. 统计高 CPU 进程正在执行什么系统调用
strace -c -p <PID>
# 3. 查看 PHP 实时调用栈(如果支持)
gdb -batch -ex "thread apply all bt" -p <PID>
# 4. 检查正在执行的 PHP 脚本(PHP-FPM 环境下)
# 查看 /proc/<PID>/cmdline 或 PHP 状态页
cat /proc/$(ps aux | grep "php-fpm.*pool" | head -1 | awk '{print $2}')/cmdline
核心思路:先锁定进程(top) → 推断它在等什么(strace) → 定位具体代码(慢日志) → 修复逻辑,请先从开启慢日志开始。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播