Docker中使用Xhprof 对代码进行性能分析

介绍

XHProf 是一个分层 PHP 性能分析工具。它报告函数级别的请求次数和各种指标,包括阻塞时间,CPU时间和内存使用情况。一个函数的开销,可细分成调用者和被调用者的开销,XHProf 数据收集阶段,它记录调用次数的追踪和包容性的指标弧在动态 callgraph 的一个程序。它独有的数据计算的报告/后处理阶段。在数据收集时,XHProfd通过检测循环来处理递归的函数调用,并通过给递归调用中每个深度的调用一个有用的命名来避开死循环。XHProf分析报告有助于理解被执行的代码的结构,它有一个简单的 HTML的 用户界面( PHP写成的)。基于浏览器的性能分析用户界面能更容易查看,或是与同行们分享成果。也能绘制调用关系图。

简单说就是查看 PHP 性能和耗时情况

Docker安装

本文演示使用仓库 dnmp

  1. 启动 PHP 容器并进入容器
     docker exec -it php71 sh
  2. 使用 docker-php-extension 安装 Xhprof 扩展
      install-php-extensions xhprof
    Docker中使用Xhprof 对代码进行性能分析
  3. php -m 查看 xhprof 扩展
    Docker中使用Xhprof 对代码进行性能分析

使用

安装成功后,可以在 PHP 代码中使用,使用 tp,在 public/index.php 文件中添加代码

//开始分析
\xhprof_enable();

require __DIR__ . '/../vendor/autoload.php';

// 要进行分析的代码,执行HTTP应用并响应
$http = (new App())->http;
//分析结束,并获取分析结果
$xhprof_data = \xhprof_disable();
var_dump($xhprof_data);
exit;

$xhprof_data 变量保存程序运行过程中所有的函数调用时间及 CPU 内存消耗

具体记录哪些指标可以通过 xhprof_enable 的参数控制,目前支持的参数有:

  1. HPROF_FLAGS_NO_BUILTINS 跳过所有内置(内部)函数。
  2. XHPROF_FLAGS_CPU 输出的性能数据中添加 CPU 数据。
  3. XHPROF_FLAGS_MEMORY 输出的性能数据中添加内存数据。

访问 tp 框架,打印分析结果

Docker中使用Xhprof 对代码进行性能分析

可以看到,虽然成功分析出来结果,但是数据对我们不是太友好

对分析结果,可以通过 xhprof 自带的 lib 库生成到一个文件里面,然后通过 xhprof 自带的 html 来显示

xhprof_html 来显示分析结果

配置 xhprof_html 的访问域名,以便我们进行访问
在 php 容器的根目录下 通过 find -name xhprof_html 搜索扩展生成的 html 的位置
Docker中使用Xhprof 对代码进行性能分析
Docker中使用Xhprof 对代码进行性能分析
/usr/local/lib/php 文件夹下,可看到两个文件夹 xhprof_htmlxhprof_lib
xhprof_html: 进行分析结果网页显示的html
xhprof_lib: 对分析结果进行其它处理的类库

配置访问域名

复制 xhprof_html,xhprof_lib 文件到 nginx 的 对外访问目录,我的 PHP 容器的 www 映射的就是 nginx 的访问目录,不在一个容器,可以先复制到宿主机,然后在复制到 nginx 容器内

# 创建 nginx 的目录
/www # mkdir /www/xhprof
/www # mkdir /www/xhprof/xhprof_html
/www # mkdir /www/xhprof/xhprof_lib

#复制 xhprof_html,xhprof_lib 到新创建的目录
/www/xhprof # cp -R /usr/local/lib/php/xhprof_html/* /www/xhprof/xhprof_html/
/www/xhprof # cp -R /usr/local/lib/php/xhprof_lib/* /www/xhprof/xhprof_lib

nginx 配置域名,并重启 nginx 服务

server {
    listen       80;
    server_name  xhprof.li;
    root   /www/xhprof/xhprof_html;
    index  index.php index.html index.htm;
    #charset koi8-r;

    access_log /dev/null;
    #access_log  /var/log/nginx/nginx.localhost.access.log  main;
    error_log  /var/log/nginx/nginx.xhprof-li.error.log  warn;

    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    location / {
        if (!-e $request_filename) {
            rewrite  ^(.*)$  /index.php?s=$1  last;
            break;
        }
    }

    location ~ \.php$ {
        fastcgi_pass   php71:9000;
        fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
        include        fastcgi-php.conf;
        include        fastcgi_params;
    }


}

分析结果显示文件

  1. 配置生成的文件输出目录,PHP.ini,手动创建下,注意权限

    [xhprof]
    # 注意目录是否有权限生成文件
    xhprof.output_dir = /www/xhprof
  2. 重启 PHP 服务

     docker-compose restart php71
  3. 更改代码,ThinkPHP6 index.php

    <?php
    // [ 应用入口文件 ]
    namespace think;
    //xhprof-开始分析
    \xhprof_enable();
    require __DIR__ . '/../vendor/autoload.php';
    //xhprof-要进行分析的代码,执行HTTP应用并响应
    //-----------------------------------------
    $http = (new App())->http;
    //-----------------------------------------
    //xhprof-分析结束,并获取分析结果
    $xhprof_data = \xhprof_disable();
    //xhprof-引入类库,进行分析结果的保存
    include_once "/www/xhprof/xhprof_lib/utils/xhprof_lib.php";
    include_once "/www/xhprof/xhprof_lib/utils/xhprof_runs.php";
    // save raw data for this profiler run using default
    // implementation of iXHProfRuns.
    $xhprof_runs = new \XHProfRuns_Default();
    // xhprof - 保存数据到 xhprof-test 文件
    $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_test");
    dd($run_id);
    $response = $http->run();
    $response->send();
    $http->end($response);
  4. 运行 tp 框架,生成文件
    Docker中使用Xhprof 对代码进行性能分析

  5. 打开刚刚配置 xhprof 域名
    Docker中使用Xhprof 对代码进行性能分析

  6. 显示结果
    Docker中使用Xhprof 对代码进行性能分析

字段名 含义
Calls 调用次数
Incl. Wall Time 调用的包括子函数所有花费时间,以微秒算
Excl. Wall Time 函数执行本身花费的时间,不包括子树执行时间,以微秒算
Incl. CPU 调用的包括子函数所有花费的cpu时间
Excl. CPU 函数执行本身花费的cpu时间,不包括子树执行时间,以微秒算
Incl.MemUse 包括子函数执行使用的内存, 以字节算
Excl.MemUse 函数执行本身内存,以字节算
Incl.PeakMemUse Incl.MemUse的峰值

可以点击 [View Full Callgraph] 链接,查看可视化分析图
如果报错 failed to execute cmd: " dot -Tsvg". stderr: 'sh: dot: not found ', 大概率是缺少依赖 graphviz

安装 graphviz

graphviz 是一个绘制图形的工具,可以更为直观的让你查看性能的瓶颈。
docker 容器内使用 apk 进行安装

  1. 进入 PHP71 容器
     docker exec -it php71 sh
  2. 安装 graphviz
     apk add graphviz --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
    Docker中使用Xhprof 对代码进行性能分析
  3. 再次点击 [View Full Callgraph]
    Docker中使用Xhprof 对代码进行性能分析

接入项目

在上面演示中,是直接通过修改框架的入口文件 index.php 来进行分析的,但不可能每个项目我们都需要修改源码
其实 PHP 本身就提供了更好的注入方式,将上述逻辑保存到 xhprof_inject.php 文件中,然后修改 PHP 配置文件中的 auto_prepend_file 配置,这样所有的 PHP 请求文件都会自动注入 xhprof_inject.php 这个文件,这样侵入性更小,并且可以实现基于站点的注入。

  1. /www/xhprof/xhprof_inject.php
    <?php
    //开启xhprof
    xhprof_enable(XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU);
    //在程序结束后收集数据
    register_shutdown_function(function() {
     $xhprof_data        = xhprof_disable();
     //让数据收集程序在后台运行
     if (function_exists('fastcgi_finish_request')) {
         fastcgi_finish_request();
     }
     //xhprof-引入类库,进行分析结果的保存
     include_once "/www/xhprof/xhprof_lib/utils/xhprof_lib.php";
     include_once "/www/xhprof/xhprof_lib/utils/xhprof_runs.php";
     // save raw data for this profiler run using default
     // implementation of iXHProfRuns.
     $xhprof_runs = new \XHProfRuns_Default();
     // xhprof - 保存数据到 xhprof-test 文件
     $xhprof_runs->save_run($xhprof_data, "xhprof_test");
    });
  2. 更改 PHP.ini 或添加 nginx参数
    ; Automatically add files before PHP document.
    ; http://php.net/auto-prepend-file
    auto_prepend_file =/www/xhprof/xhprof_inject.php
    更改完重启 PHP 容器
    如果不想修改 PHP 配置文件,也可修改 Nginx 的 fastcgi_param
    fastcgi_param PHP_VALUE "auto_prepend_file=/www/xhprof/xhprof_inject.php";
    修改完后重启 Nginx 服务
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!