本文目录导读:

- 第一步:确认是否服务器资源耗尽(最宏观)
- 第二步:排查是否IO瓶颈(慢在磁盘)
- 第三步:排查具体进程与服务(微观定位)
- 第四步:排查代码层面(最核心)
- 第五步:数据库排查(最大瓶颈)
- 第六步:工具辅助排查(进阶)
- 标准排查命令速查表
- 紧急处置建议
排查 PHP 项目服务器卡顿问题,通常需要从系统资源、PHP自身、数据库、应用代码四个层面入手,遵循从宏观到微观的顺序。
以下是标准排查流程(针对Linux服务器):
第一步:确认是否服务器资源耗尽(最宏观)
登入服务器,第一时间使用以下命令查看系统负载。
top或htop:查看CPU、内存使用率,以及load average(负载均值)。- 负载值 > CPU核心数,说明有进程在排队,系统繁忙。
- 观察
%CPU列,看是否有php-fpm或mysqld进程占用过高。 - 观察
%MEM列,看内存是否接近100%。
free -h:查看物理内存和Swap(交换分区)。如果Swap使用很高(>0),通常意味着物理内存不足,频繁进行磁盘IO,导致卡顿。
df -h:查看磁盘空间。- 或
/tmp目录使用率达到100%,会导致PHP无法写入会话文件、日志或临时文件,直接卡死。
- 或
vmstat 1 5:每秒刷新一次,共5次,关注r(运行队列) 和wa(IO等待)。r> CPU核心数 => CPU不足。wa> 20% => 磁盘读写太慢或存在瓶颈。
第二步:排查是否IO瓶颈(慢在磁盘)
如果vmstat显示wa高,或者top里进程状态是D(不可中断睡眠),基本是IO问题。
iostat -x 1:查看每个磁盘的IO状况。%util接近100%:磁盘已满负荷。await非常高(>50ms):磁盘响应慢(可能是机械盘坏道、云盘性能不足)。
iotop:直接查看是哪个进程在疯狂读写硬盘(如日志切割、MySQL大量写操作)。
第三步:排查具体进程与服务(微观定位)
确认资源未耗尽,则进入应用层排查。
- 查看PHP-FPM进程:
ps aux | grep php-fpm | wc -l:查看子进程数量。- 如果子进程数达到
pm.max_children设定值,说明请求正在排队等待。 - 观察每个PHP进程占用的内存(
RSS),如果单个进程占用几十上百MB,可能存在内存泄漏。
- 查看慢日志:
- 找到
php-fpm.conf中的request_slowlog_timeout(通常设为 2s 或 5s)。 - 查看慢日志文件(
slowlog),里面记录了哪一行PHP代码执行超时。这是最直接定位到具体代码的方法。
- 找到
- 查看错误日志:
- 检查
/var/log/php-fpm/或 Nginx日志,看是否有报错(如超时、内存耗尽、致命错误)。
- 检查
第四步:排查代码层面(最核心)
如果PHP进程正常,但接口就是慢,需要深入代码。
- 是否有死循环或大量计算?
- 使用
strace -p [PHP进程PID]:跟踪系统调用,如果长时间卡在某个循环或计算中,能看到调用栈。
- 使用
- 接口响应慢?
- 外部API调用: 代码是否调用了另一个慢的外部API?如果第三方接口5秒没响应,当前进程就阻塞5秒。
- 文件操作: 是否在请求中频繁读写小文件?
- Session阻塞: 如果未用文件锁或Redis,PHP默认使用文件存储Session,并发请求同一用户时,后一个请求会等前一个释放Session锁。
第五步:数据库排查(最大瓶颈)
80%的“PHP卡顿”实际是数据库查询慢导致的。
- 开启慢查询日志:
- 在MySQL配置中设置
slow_query_log = 1,long_query_time = 2。 - 查看MySQL慢日志,找到执行时间超过2秒的SQL语句。
- 在MySQL配置中设置
- 即时查看数据库状态:
- 在MySQL命令行执行
SHOW FULL PROCESSLIST;,看有没有很多State: Sending data、State: Locked的查询。 - 如果有大量
Locked,说明有锁表问题。 - 如果有大量
Sending data,通常意味着SQL没有走索引,全表扫描。
- 在MySQL命令行执行
第六步:工具辅助排查(进阶)
当上述手段无法精准定位时,使用APM(应用性能监控)工具:
- Xdebug:本地开发环境,生成Call Grind文件,用
QCacheGrind或WebGrind分析执行瓶颈。 - XHProf / Tideways:生产环境推荐(性能损耗小),能记录每个函数的调用次数和执行时间。
- 开源APM:
- Pinpoint (需要额外部署)
- SkyWalking (Java/PHP)
标准排查命令速查表
| 命令 | 作用 | 看什么指标 |
|---|---|---|
uptime |
系统负载 | load average |
top |
进程资源 | %CPU, %MEM, load |
free -h |
内存 | used, swap |
df -h |
磁盘 | Use% |
vmstat 1 |
整体状态 | r(进程), wa(IO) |
iostat -x 1 |
磁盘性能 | %util, await |
strace -p pid |
跟踪进程系统调用 | 卡在哪个系统调用(fcntl, read, wait) |
SHOW FULL PROCESSLIST |
数据库当前查询 | Time, State, Info |
tail -f 慢日志 |
PHP慢请求 | 具体卡在哪一行代码 |
紧急处置建议
- 如果CPU飙升:找
top里CPU最高的PHP进程,用strace看它在干嘛,或重启PHP-FPM(治标)。 - 如果IO占满:找到
iostat或iotop里写最大的进程(通常是不合理的日志记录或数据库查询),先停掉该进程或命令。 - 如果内存不够:临时释放缓存
echo 3 > /proc/sys/vm/drop_caches(有风险,仅作为临时应急手段)。
推荐路径: top/htop -> 看CPU/MEM -> vmstat看IO -> 看PHP错误日志 -> 看MySQL慢查询日志,通常走完前三步就能锁定70%的问题。