最常见原因是slowlog和request_slowlog_timeout未同时启用或日志路径不可写;必须删除两行前的分号,确保父目录存在且属主为www/www-data,超时值须带单位(如2s),并重载php-fpm服务。

slowlog 文件为空或只有报错行,根本没堆栈
最常见原因是 slowlog 和 request_slowlog_timeout 没同时启用,或者路径不可写。PHP-FPM 不会报错中断,而是静默跳过记录。
-
slowlog行前面的分号;必须删掉,否则等于注释——这是宝塔和手动编辑时最高频的遗漏点 - 日志路径父目录(如
/www/wwwlogs/或/var/log/php-fpm/)必须存在,且属主为 PHP-FPM 实际运行用户(通常是www或www-data),用ls -ld /www/wwwlogs/确认 -
request_slowlog_timeout = 0表示关闭,必须设成带单位的值,如2s、5s,不能写5(无单位默认是秒但部分版本不兼容) - 改完配置后必须执行重载:
systemctl reload php-fpm(CentOS)或systemctl reload php8.2-fpm(Ubuntu/Debian),仅保存不生效
日志里有堆栈但看不懂调用链,定位不到具体代码行
PHP-FPM 慢日志的 backtrace 是从阻塞点向上回溯的函数调用,不是完整堆栈,也不含变量值。关键看最后两行:最末行是当前卡住的函数,倒数第二行是它的直接调用者。
- 例如日志中出现:
[0x00007f8b1c0a1234] curl_exec() /www/wwwroot/site.com/api.php:87,说明第 87 行的curl_exec()阻塞了,问题就在这一行或它依赖的上游逻辑 - 如果反复看到
PDOStatement::execute或mysqli_query,不是代码写得差,大概率是 SQL 缺索引、锁表,或没设查询超时(PDO::ATTR_TIMEOUT) -
file_get_contents()、curl_exec()出现在末尾,基本可断定是外部 HTTP 请求未设超时,而非业务逻辑本身慢 - 注意:慢日志不记录 DNS 解析、TCP 连接建立、SSL 握手等前置耗时,只记录 PHP 进入执行阶段后的阻塞点
用命令快速统计慢请求来源和高频卡点
不用人工翻日志,几条 shell 命令就能筛出规律。假设日志路径是 /www/wwwlogs/php_slow.log:
- 查最近 100 条中调用最多函数:
awk '/\[0x/{print $NF}' /www/wwwlogs/php_slow.log | sort | uniq -c | sort -nr | head -10 - 按脚本路径聚合耗时次数:
awk '/script_filename/{f=$NF} /\[0x/{print f}' /www/wwwlogs/php_slow.log | sort | uniq -c | sort -nr - 提取所有 URL(需日志含
HTTP_HOST和REQUEST_URI字段):awk '/HTTP_HOST/{h=$NF} /REQUEST_URI/{u=$NF; print h u}' /www/wwwlogs/php_slow.log | head -10
这些输出能立刻暴露是某个接口、某类数据库操作,还是特定第三方调用在拖慢整体响应。
为什么开了 slowlog 还抓不到真实卡顿?几个硬性限制
PHP-FPM 慢日志只覆盖「PHP 脚本执行阶段」,很多你以为的“慢”,它根本看不见。
- Nginx 转发耗时、TLS 握手、客户端网络延迟 —— 全部不计入
request_slowlog_timeout计时范围 - 数据库连接建立时间(
new PDO()的那一刻)不被记录,只有->query()或->execute()执行时才开始计时 - CLI 脚本、定时任务、WebSocket 后端 —— 任何非 FPM SAPI 模式都不触发 slowlog
- PHP 7.4+ 默认不统计 IO 阻塞时间(如
sleep()、usleep()),只统计 CPU 占用时间;若想捕获 sleep 类卡顿,需额外开启php_admin_flag[slowlog_trace_io] = on(部分版本支持)
真正卡在哪儿,得先确认是不是 PHP-FPM 责任区。如果不是,就得去查 Nginx access_log 的 $upstream_response_time,或者用 tcpdump 抓包看网络层耗时。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











