服务器响应变慢了,你打开 top 看到一排 php-fpm 进程在跑,但到底哪个 URL 在吃资源?哪段代码是元凶?top 告诉不了你这些。phptop 可以。
安装
git clone https://github.com/bearstech/phptop.git /opt/phptop
不需要 composer,不需要 PECL 扩展。要求 PHP >= 5.2.0,实测兼容到 PHP 8.2。
phptop 的命令行端是一个 Perl 脚本,运行前需要确保系统安装了 Perl 及相关依赖:
# Debian/Ubuntu
apt-get install -y perl libterm-size-perl libtime-parsedate-perl libipc-run-perl libfile-readbackwards-perl
# CentOS/RHEL
yum install -y perl perl-Term-Size perl-Time-ParseDate perl-IPC-Run perl-File-ReadBackwards
原理
phptop 分两部分协作:
-
采集端(PHP):通过
auto_prepend_file在每个 PHP 请求执行时自动注入代码,用getrusage()和memory_get_peak_usage()采集该请求的耗时、CPU 时间和内存峰值,然后调用error_log()写入 PHP 错误日志 - 展示端(Perl):解析 PHP 错误日志中的 phptop 数据,按 URL 聚合统计后输出类似 top 的表格
所以它依赖的是 PHP 标准的 error_log() 函数,不需要额外的扩展或服务。

激活
只需要一行配置:
# 在 php.ini 或 fpm 的 pool 配置中追加一行
echo "auto_prepend_file=/opt/phptop/phptop_hook.php" >> /etc/php/8.2/fpm/php.ini
# 重载 PHP-FPM 使配置生效
systemctl reload php8.2-fpm
如果是 Apache + mod_php:
apache2ctl reload
如果是 Nginx + PHP-FPM,还需要确保 FPM 的 worker 输出被捕获到日志文件中。在 FPM pool 配置(通常是 /etc/php/8.2/fpm/pool.d/www.conf)中确认或添加:
catch_workers_output = yes
php_admin_value[error_log] = /var/log/php-fpm/error.log
然后重载 PHP-FPM。
等几分钟积累一些请求数据后就可以使用了。
使用
Apache(默认模式)
Apache 环境下 phptop 默认读取 Apache 错误日志,直接运行:
/opt/phptop/phptop
Nginx + PHP-FPM(指定日志)
Nginx 环境下需要用 -l 参数指定 FPM 的错误日志路径:
/opt/phptop/phptop -l /var/log/php-fpm/error.log
输出效果如下(默认按请求数排序):

各列含义:
| 列 | 说明 |
|---|---|
| Hit | 采样周期内的请求次数 |
| Time | 累计墙钟时间(秒),即用户感受到的响应时间总和 |
| User | 累计用户态 CPU 时间(秒) |
| Sys | 累计内核态 CPU 时间(秒) |
| Mem/hit | 平均每次请求内存占用(MB) |
| Mem_max | 单次请求最大内存峰值(MB) |
默认展示最近 300 秒(5 分钟)的数据,可用 -t 参数调整时间窗口。
按指标排序
默认按请求数排序。实际排查时更常用的是按内存或耗时排序。
按响应时间排序,一眼看出最慢的接口:
/opt/phptop/phptop -l /var/log/php-fpm/error.log -s time

按内存消耗排序,找出吃内存大户:
/opt/phptop/phptop -l /var/log/php-fpm/error.log -s mem

加上 -a 参数可以显示每次请求的平均值而非累计值:
/opt/phptop/phptop -l /var/log/php-fpm/error.log -s time -a
比如你发现某个接口 Time 列特别高,那就去查这个接口的代码逻辑;如果 Mem_max 异常大,大概率是有地方在循环里往数组塞数据。
排查实战
场景一:某个页面突然变慢
运行 phptop -s time,一眼看到 /api/report 的累计耗时最高,而其他接口都很低。定位到具体 URL 后,再去查对应代码的数据库查询或者外部 API 调用。
场景二:服务器内存持续增长
运行 phptop -s mem,发现 /feed 接口的 Mem_max 明显高于其他接口,Hit 数又很高。一看代码,原来是在循环里做 XML 拼接没有释放中间变量。
场景三:CPU 负载高但不知道谁导致的
运行 phptop -s cpu,User + Sys 两列直接告诉你哪个 URL 在疯狂算东西。通常是正则回溯、加密解密、或者大数组操作。
关闭和清理
排查完毕后记得关掉,毕竟 auto_prepend_file 对每个请求都有少量开销:
# 从 php.ini 中删掉那行配置
sed -i '/auto_prepend_file.*phptop/d' /etc/php/8.2/fpm/php.ini
# 重载 PHP-FPM
systemctl reload php8.2-fpm
phptop 的数据都写在 PHP 错误日志中,不需要额外清理临时文件。如果之前为了 phptop 修改了 FPM 的 catch_workers_output 或 error_log 配置,也可以一并还原。
其他常用选项
# 只看前 5 名
/opt/phptop/phptop -l /var/log/php-fpm/error.log -c 5
# 只看路径,忽略域名
/opt/phptop/phptop -l /var/log/php-fpm/error.log -p
# 分析最近 1 小时的数据
/opt/phptop/phptop -l /var/log/php-fpm/error.log -t 3600
# 输出为 HTML 格式(适合嵌入监控页面)
/opt/phptop/phptop -l /var/log/php-fpm/error.log -o html
注意事项
- 数据有延迟,不是实时的——它基于已完成的请求采样,默认展示最近 5 分钟的数据
- 只统计被 hook 到的请求,CLI 模式下的 php 脚本不会被记录
- 在高并发站点上日志量会比较大,建议排查完问题后及时关闭
- 权限要求:运行 phptop 的用户需要有读取 PHP 错误日志文件的权限
- 终端宽度不足时会报错,可通过设置
COLUMNS=120环境变量解决
phptop 从 2009 年就在用了,Bearstech 在大量生产环境上跑了多年没出过问题。对于"我的 PHP 站点哪个接口在拖后腿"这个问题,它是最快的答案。
原文标题: [bearstech/phptop]像 top 一样查看 PHP 请求的资源消耗
原文地址: https://phpreturn.com/index/a6a1686ae350e4.html
原文平台: PHP武器库
版权声明: 本文由phpreturn.com(PHP武器库官网)原创和首发,所有权利归phpreturn(PHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。