PHPCPU占用高怎么定位

wen PHP项目 1

本文目录导读:

PHPCPU占用高怎么定位

  1. 第一层:快速定位到具体进程
  2. 第二层:深入 PHP 内部
  3. 第三层:分析与解决常见原因
  4. 第四层:短期应急与常态监控
  5. 总结命令清单

定位 PHP CPU 占用高的问题,通常需要结合系统工具PHP 自身以及代码逻辑三个层面进行排查,以下是系统的定位步骤:

第一层:快速定位到具体进程

首先找出是哪个 PHP 进程导致的问题。

  1. top / htop (实时查看)

    • 执行 top,按 P (大写 P)按 CPU 降序排列。
    • 确认消耗 CPU 的进程是 php-fpmphp-cli(脚本)还是 httpd(模组方式)。
    • 记录下高负载的 PID (进程ID)。
    • 注意:对于 php-fpm,如果多个 worker 很高,那是并发问题;如果只有 1 个极高,那是单个请求有问题。
  2. strace (跟踪系统调用,看它在干什么)

    • 对有问题的 PID 执行:strace -cp <PID> (统计系统调用耗时)
    • 或者实时跟踪:strace -T -p <PID>-T 显示每个调用的耗时)
    • 观察点
      • 是否大量调用 read / write? -> 磁盘 I/O 瓶颈。
      • 是否大量 connect / sendto? -> 网络请求数据库 慢。
      • 是否非常多 nanosleep? -> 代码里有睡眠、轮询或锁等待。

第二层:深入 PHP 内部

既然确认了是 PHP 问题,继续看它在运行什么代码。

  1. 检查 php-fpm 慢日志 (最高效的方法)

    • 修改 php-fpm.confwww.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 文件、哪一行函数卡住了,这是最直接的定位方式。
  2. 使用 pmap 查看内存映射 (排查死循环或内存泄漏)

    • pmap -x <PID> | sort -k 3 -rn | head -10
    • 如果发现大量 [anon] 段,或内存异常大,可能存在循环分配或大数组操作。
  3. gdb 抓取调用栈 (终极手段,适合无慢日志环境)

    • 安装 gdb 并确保 PHP 安装了 debug 符号包(或带 --enable-debug 编译)。
    • 执行:gdb -p <PID>
    • (gdb) 提示符下输入:
      set pagination off
      thread apply all bt
    • 这会打印所有线程的堆栈。寻找 execute_exzend_vm_execute 调用链,看它卡在哪个函数上。

第三层:分析与解决常见原因

定位到具体文件后,根据现象分析原因:

现象 可能原因 解决方案
数据库查询慢 慢日志中显示大量 mysql_query / PDO->query 开启数据库慢查询日志
为查询添加索引
使用 EXPLAIN 分析SQL
大量 file_get_contents / curl 请求外部 API 或读取文件无限阻塞 设置 curl 超时时间(如 CURLOPT_TIMEOUT
使用异步并发或队列处理
无限循环 for(;;)while(true) 在循环内增加 break 条件或计数限制
正则表达式回溯 使用了类似 的复杂正则匹配长字符串 使用 preg_matchPREG_UNMATCHED_AS_NULL 或限制匹配长度,避免灾难性回溯
session 文件锁阻塞 高并发下 session_start() 锁等待 高并发场景改用 Redis/Memcached 存储 session
OpCache 未开启 每次请求重复解析、编译 PHP 文件 开启 OpCache,设置合适的 opcache.validate_timestamps
OOM (内存不足) 导致频繁交换 物理内存耗尽,系统频繁 swap,I/O 飙升导致 CPU 软中断 排查内存泄漏,或增加物理内存

第四层:短期应急与常态监控

  • 应急重启systemctl restart php-fpmkill -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) → 定位具体代码(慢日志) → 修复逻辑,请先从开启慢日志开始。

抱歉,评论功能暂时关闭!