PHP 怎么排查性能问题

wen PHP项目 3

本文目录导读:

PHP 怎么排查性能问题

  1. 基础排查方法
  2. 专业工具使用
  3. 实时监控工具
  4. 数据库性能排查
  5. 内存泄漏排查
  6. 完整排查流程
  7. 性能优化建议
  8. 实用命令行工具汇总
  9. 建议采用的分层排查策略

我来详细介绍 PHP 性能问题的排查方法和工具,从简单的到专业的逐步深入。

基础排查方法

简单日志分析

// 开启慢查询日志(PHP-FPM)
; php.ini 配置
request_slowlog_timeout = 5s
request_slowlog_file = /var/log/php-fpm/slow.log

代码级计时

// 简单的代码计时
$start = microtime(true);
// 你的代码
$elapsed = microtime(true) - $start;
error_log("执行时间: {$elapsed}s");

自带函数分析

// 使用 PHP 内置的性能函数
$start = memory_get_usage();
// 代码
$peak = memory_get_peak_usage();

专业工具使用

Xdebug Profiler

// php.ini 配置
[xdebug]
xdebug.mode = profile
xdebug.output_dir = /tmp/profiler
xdebug.profiler_output_name = cachegrind.out.%p
// 生成的分析文件需要用工具查看

使用 PhpStormKCacheGrind 查看:

# 安装分析工具
sudo apt-get install kcachegrind
# 打开分析文件
kcachegrind /tmp/profiler/cachegrind.out.12345

XHProf / Tideways

// XHProf 安装(php 8.0+ 推荐)
pecl install xhprof
// 配置
[xhprof]
extension=xhprof.so
xhprof.output_dir="/tmp/xhprof"
// 使用示例
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
// 你的代码
$data = xhprof_disable();

Blackfire.io

// 专业性最强的工具
// 安装扩展
composer require blackfire/php-sdk
// 使用示例
$probe = new \Blackfire\Probe();
$probe->enable();
// 你的代码
$probe->disable();

实时监控工具

PHP-FPM 状态页面

# nginx 配置
location ~ ^/fpm-status$ {
    access_log off;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/var/run/php-fpm.sock;
}

使用 top/htop 监控

# 查看进程 CPU 占用
top -H -p $(pgrep -f php-fpm | head -1)
# 实时查看 PHP-FPM 进程
htop | grep php-fpm

strace 系统调用分析

# 跟踪 PHP 进程的系统调用
strace -p PID -f -e trace=file,network,memory
# 统计各类系统调用
strace -c -p PID

数据库性能排查

慢查询日志

-- MySQL 配置
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2;
-- 查看慢查询
SHOW VARIABLES LIKE 'slow_query_log%';

数据库查询分析

// 使用 Laravel 查询分析
DB::listen(function ($query) {
    Log::info($query->sql, $query->bindings, $query->time);
});

内存泄漏排查

内存监控

// 监测内存使用
$memory_cache = [];
function memory_usage() {
    $size = memory_get_usage(true);
    $unit = ['b','kb','mb','gb'];
    return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}
// 定期输出
register_tick_function(function() {
    if (memory_get_usage() > 100 * 1024 * 1024) {
        error_log("内存使用过高: " . memory_get_usage());
    }
});

完整排查流程

系统级检查

# 检查整体性能
top -u www-data
free -m
iostat -x 1
vmstat 1
# 检查 PHP-FPM 状态
/usr/sbin/php-fpm -t
systemctl status php-fpm

应用级检查清单

// 性能检查清单
[
    '响应时间' => '正常 < 200ms,慢查询 > 500ms',
    '内存使用' => '单请求 < 64M,平局 < 32M',
    'CPU使用' => '高峰 < 80%,平均 < 40%',
    '数据库'  => '查询时间 > 1s 需要优化',
    '缓存'   => 'Redis 命中率 > 95%',
    '流量'   => 'Nginx 错误日志要关注 5xx',
]

常见性能问题定位

// 场景1:页面加载慢
// - 检查网络请求时间
// - 数据库查询次数和效率
// - PHP 执行时间
// - Redis/缓存使用情况
// 场景2:内存溢出
// - 是否有循环引用
// - 是否无限递归
// - 是否处理超大数组
// - 是否有未释放的资源
// 场景3:CPU 过高
// - PHP 无限循环
// - 大量正则操作
// - 复杂的算法
// - 循环 SQL 查询

性能优化建议

// 1. 使用 OPcache
[opcache]
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
// 2. 使用关系缓存
// Redis 示例
$redis = new Redis();
$cache_key = 'product_' . $id;
if (!$data = $redis->get($cache_key)) {
    $data = $this->getProduct($id);
    $redis->set($cache_key, serialize($data), 3600);
}
// 3. 数据库索引
// 确保常用查询字段都有索引
CREATE INDEX idx_product_id ON products (product_id);
// 4. 批量处理
// 不要循环插入
DB::table('users')->insert($bulkData); // 批量插入

实用命令行工具汇总

# 常用命令汇总
php -i | grep "Configure"          # PHP 配置信息
php -m                             # 启用模块
php --ini                          # 加载的配置文件
# 内存和CPU
pidstat -p PID 1                   # 进程性能
sar -u 1 3                         # CPU 使用率
sar -r 1 3                         # 内存使用率
# 网络
netstat -an | grep :80             # 端口连接
iftop                              # 流量监控
# 应用日志
tail -f /var/log/php-fpm/error.log
tail -f /var/log/nginx/access.log

建议采用的分层排查策略

  1. 第一层:先看响应时间和错误日志
  2. 第二层:检查服务器资源(CPU、内存、IO)
  3. 第三层:分析数据库查询和索引
  4. 第四层:使用 Profiler 找出具体函数耗时
  5. 第五层:代码审查,算法优化

最后建议:先解决 80% 的大问题(如 N+1 查询、缓存缺失),再优化小细节,不要过度优化,确保可维护性。

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