《让php扩展开拓编程前路》 之 性能分析利器 xhprof | php 技术论坛-380玩彩网官网入口

  • title: 《让php扩展开拓编程前路》 之 性能分析利器 xhprof
  • tag: peclphpprofilerxhprof性能分析
  • author: tacks
  • create-date: 2023-05-16
  • update-date: 2023-05-18

ref

  • wiki
  • pecl
  • php
  • php
  • php
  • github
  • github
  • github
  • github
  • github
  • github
  • github
  • github
  • github
  • github
  • blog @facebook
  • packagist
  • blog

1、intro

1.1 xhprof 的发展

php 扩展 xhprof 是一个轻量级的分层性能测量分析器,最开始由 facebook 开发 ,用于分析和优化 php web 网站,在2009年开源,大概2015年不再维护,facebook/xhprof 代码转到 仓库维护。后来基于 facebook 的代码,出现了很多 xhprof 分支。从 pecl 上可以看到 扩展,不过中途也是有更换开发者,2013 年最新版到 是由 仓库维护,当时主要是 php5.x 系列,随着 php7.x 系列的更新,php底层数据类型实现进行优化,之前 xhprof 版本无法在 php7.x 上运行,于是更换成 ,截至目前 2023年05月 xhprof 最新版本是 。还好后继有人,xhprof 依然活跃,可谓是 xhprof 的第二世!第三世其实是 tideways_xhprof,当然本文暂且先不讨论 tideways 相关扩展。

xhprof 扩展 是 php 的函数级层次分析器,具有简单的基于 html 的可视化界面。原始数据收集组件是用 c 语言实现的(作为 php 扩展)。性能分析展示层全部使用 php。它能够报告函数级包含和独占的挂起时间、内存使用情况、cpu 时间和每个函数的调用次数,以及整个的函数调用图。

当然 xhprof 有很多衍生的版本项目,虽然他们名字可能一样,但可能不是同一套代码,因此建议直接去看 github 上的代码。

本文讨论的 xhprof 扩展来源如下

  • pecl
  • github

1.2 什么是 profiler 分析器 ?

profiler 分析器是一种用于监控并优化程序性能的工具,它可以找出应用程序中的性能瓶颈,从而帮助开发人员提高程序的响应速度和性能。

通常来说,它可以收集程序执行期间的各种指标和性能数据,包括但不限于,cpu使用率、内存使用情况、函数执行时间等,然后生成详细的性能分析报告,以及可视化的图表展示。

  • 工具选择
    • php 中,比如有 xdebugxhproftideways
    • 其他语言,如 go 中,比如 pprofdlvgo-torch
  • 工具集成
  • 应用程序执行
  • 工具收集数据
  • 可视化报告展示
    • 函数调用频次
    • 函数调用关系、调用链
    • 函数执行耗时
    • 函数内存消耗
    • 火焰图 flame graph
    • 堆栈图 call graph

2、prepare

2.1 我的环境

  • php 7.3.20 没有是最新的是因为我太懒,晚点换 :bowtie:
[root@centos7 ~]# php -v
php 7.3.20 (cli) (built: jan 11 2021 17:21:40) ( nts )
380玩彩网官网入口 copyright (c) 1997-2018 the php group
zend engine v3.3.20, 380玩彩网官网入口 copyright (c) 1998-2018 zend technologies
    with zend opcache v7.3.20, 380玩彩网官网入口 copyright (c) 1999-2018, by zend technologies
[root@centos7 ~]# /php/php73/bin/pecl -v
pear version: 1.10.12
php version: 7.3.20
zend engine version: 3.3.20
running on: linux centos7 3.10.0-1160.11.1.el7.x86_64 #1 smp fri dec 18 16:34:56 utc 2020 x86_64
[root@centos7 ~]# cat /etc/redhat-release
centos linux release 7.9.2009 (core)

2.2 安装 xhprof 扩展

  • pecl 安装 xhprof
    • 如果是针对 php5.x 的,需要安装 xhprof-0.9.4 版本
    • 如果是针对 php7.0 以上,则直接安装 xhprof 也就是最新版
[root@centos7 ~]# /php/php73/bin/pecl install xhprof
....
build process completed successfully
installing '/php/php7.3.20/lib/php/extensions/no-debug-non-zts-20180731/xhprof.so'
install ok: channel://pecl.php.net/xhprof-2.3.9
configuration option "php_ini" is not set to php.ini location
you should add "extension=xhprof.so" to php.ini
  • 配置 php.ini 增加 xhprof 配置 xhprof.output_dir
# 创建目录
[root@centos7 ~]# mkdir -p /tmp/php-xhprof/output
# 追加配置
[root@centos7 ~]# vim  /php/php7.3.20/lib/php.ini
[xhprof]
extension=xhprof.so
xhprof.output_dir=/tmp/php-xhprof/output
# 重启
[root@centos7 ~]# /etc/init.d/php-fpm73 restart
gracefully shutting down php-fpm . done
starting php-fpm  done
  • 检查 xhprof 是否被加载
[root@centos7 ~]# php73 -m | grep xhprof
xhprof
[root@centos7 ~]# php --ri
xhprof
xhprof support => enabled
version => 2.3.9
directive => local value => master value
xhprof.output_dir => /tmp/php-xhprof/output => /tmp/php-xhprof/output
xhprof.collect_additional_info => 0 => 0
xhprof.sampling_interval => 100000 => 100000
xhprof.sampling_depth => 2147483647 => 2147483647

2.3 其他准备

# 为防止需要图片相关依赖
[root@centos7 ~]# yum install libpng -y
[root@centos7 ~]# yum install graphviz -y
# 为性能数据采集准备
[root@centos7 php-xhprof]# php -m | grep -e "mongodb|xhprof"
mongodb
xhprof

3、ues profiler

3.1 xhprof 相关函数说明

    • $flags 配置
      • xhprof_flags_no_builtins 跳过所有内置函数
      • xhprof_flags_cpu 输出的性能数据中添加 cpu 数据
      • xhprof_flags_memory 输出的性能数据中添加内存数据
    • $options
      • 忽略性能分析中的某些函数
    • 返回值就是本次采集的 xhprof_data 数据

3.2 在 cli 中使用 xhprof 进行性能分析

3.2.1 引入 longxinh/xhprof 一些类库

  • 创建一个项目目录 /code/php-xhprof
  • 拉取 代码
  • 创建一个测试目录 /code/php-xhprof/testcli
  • 复制 longxinh/xhprof 代码目录中的 xhprof_html xhprof_lib 代码目录到 testcli
[root@centos7 ~]# mkdir -p /code/php-xhprof
[root@centos7 ~]# mkdir -p /code/php-xhprof/testcli
[root@centos7 ~]# cd /code/php-xhprof
[root@centos7 php-xhprof]# git clone https://github.com/longxinh/xhprof
[root@centos7 php-xhprof]# cd /code/php-xhprof/testcli
[root@centos7 testcli]# cp -r  /code/php-xhprof/xhprof/xhprof_*  /code/php-xhprof/

3.2.2 在 testcli 目录下创建测试脚本 test.php

[root@centos7 testcli]# touch /code/php-xhprof/testcli/test.php
[root@centos7 php-xhprof]# tree -l 2
.
├── testcli
│   ├── inject.php
│   └── test.php
├── xhprof
│   ├── bin
│   ├── changelog
│   ├── credits
│   ├── examples
│   ├── extension
│   ├── license
│   ├── package.xml
│   ├── readme.md
│   ├── resource
│   ├── scripts
│   ├── support
│   ├── travis
│   ├── xhprof_html
│   └── xhprof_lib
├── xhprof_html
│   ├── callgraph.php
│   ├── css
│   ├── docs
│   ├── index.php
│   ├── jquery
│   ├── js
│   └── typeahead.php
└── xhprof_lib
    ├── display
    └── utils

3.2.3 编写测试脚本 test.php


// 开启 xhprof
xhprof_enable(xhprof_flags_no_builtins  xhprof_flags_cpu  xhprof_flags_memory);
function test($i) {
    if($i == 0) {
        return 1;
    } else {
        return $i * test($i - 1);
    }
};
$res = test(3);
var_dump($res); // 函数执行结果
// 结束 xhprof
$xhprof_data = xhprof_disable();
var_dump($xhprof_data); // xhprof 收集到的数据

// 下面与 xhprof 扩展无关,而是 php 序列化 xhprof_data 的数据,并生成一个文件
// 将收集到的数据 序列化存储到 xhprof.output_dir 目录中,生成一个唯一的文件,返回 文件 run_id
$xhprof_root = realpath(dirname(__file__) . '/..');
include_once $xhprof_root . "/xhprof_lib/utils/xhprof_lib.php";
include_once $xhprof_root . "/xhprof_lib/utils/xhprof_runs.php";
$xhprof_runs = new xhprofruns_default();
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_testcli");
var_dump($run_id);

3.2.4 执行测试脚本 test.php

[root@centos7 php]# php test.php
int(6)
array(5) {
  ["test@2==>test@3"]=>
  array(5) {
    ["ct"]=>
    int(1)
    ["wt"]=>
    int(2)
    ["cpu"]=>
    int(11)
    ["mu"]=>
    int(832)
    ["pmu"]=>
    int(0)
  }
  ["test@1==>test@2"]=>
  array(5) {
    ["ct"]=>
    int(1)
    ["wt"]=>
    int(13)
    ["cpu"]=>
    int(13)
    ["mu"]=>
    int(1408)
    ["pmu"]=>
    int(0)
  }
  ["test==>test@1"]=>
  array(5) {
    ["ct"]=>
    int(1)
    ["wt"]=>
    int(16)
    ["cpu"]=>
    int(16)
    ["mu"]=>
    int(1984)
    ["pmu"]=>
    int(0)
  }
  ["main()==>test"]=>
  array(5) {
    ["ct"]=>
    int(1)
    ["wt"]=>
    int(26)
    ["cpu"]=>
    int(27)
    ["mu"]=>
    int(2560)
    ["pmu"]=>
    int(0)
  }
  ["main()"]=>
  array(5) {
    ["ct"]=>
    int(1)
    ["wt"]=>
    int(69)
    ["cpu"]=>
    int(67)
    ["mu"]=>
    int(3160)
    ["pmu"]=>
    int(0)
  }
}
string(13) "646329afc4f30"

3.2.5 查看 xhprof 收集的数据文件

[root@centos7 php]# cat /tmp/php-xhprof/output/646329afc4f30.xhprof_testcli.xhprof
a:5:{s:15:"test@2==>test@3";a:5:{s:2:"ct";i:1;s:2:"wt";i:2;s:3:"cpu";i:11;s:2:"mu";i:832;s:3:"pmu";i:0;}s:15:"test@1==>test@2";a:5:{s:2:"ct";i:1;s:2:"wt";i:13;s:3:"cpu";i:13;s:2:"mu";i:1408;s:3:"pmu";i:0;}s:13:"test==>test@1";a:5:{s:2:"ct";i:1;s:2:"wt";i:16;s:3:"cpu";i:16;s:2:"mu";i:1984;s:3:"pmu";i:0;}s:13:"main()==>test";a:5:{s:2:"ct";i:1;s:2:"wt";i:26;s:3:"cpu";i:27;s:2:"mu";i:2560;s:3:"pmu";i:0;}s:6:"main()";a:5:{s:2:"ct";i:1;s:2:"wt";i:69;s:3:"cpu";i:67;s:2:"mu";i:3160;s:3:"pmu";i:0;}}

3.2.6 xhprof_data 数据涵义

字段 涵义
ct 函数被调用的次数
wt 函数的执行时间耗时
cpu 函数消耗的cpu时间
mu 函数方法使用的内存
pmu 函数方法使用的峰值内存

3.2.6 查看 xhprof 可视化报告分析

  • 只有数据没有图看起来很费劲,别忘记了,它有自带的可视化配置 html

  • nginx 配置 web ui ,然后重启 nginx, 可以访问 xhprof.tacks.com

server {
    listen  80;
    server_name xhprof.tacks.com;
    # 配置 xhprof html 根目录
    root /code/php-xhprof/xhprof_html/;
    index index.html index.php;
    access_log /logs/tacks/xhprof.tacks.com-access.log;
    error_log /logs/tacks/xhprof.tacks.com-error.log;
    rewrite_log on;
    location / {
            try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param script_filename $document_root$fastcgi_script_name;
        fastcgi_param server_software nginx;
        include fastcgi_params;
    }
}
  • 针对本例,应该访问 http://xhprof.tacks.com/index.php?run=646329afc4f30&source=xhprof_testcli

646329afc4f30 表格

字段 涵义
function name 函数名
calls 调用次数
incl. wall time (microsec) 函数运行时间(包括子函数)
iwall% 函数运行时间(包括子函数)占比
excl. wall time (microsec) 函数运行时间(不包括子函数)
ewall% 函数运行时间(不包括子函数)占比
[view full callgraph] 函数调用链图 (需要graphviz)

646329afc4f30 函数调用

  • 具体展示图表可以看本文 4.1 章节

3.2.7 分析所有 php 脚本文件

  • 编写 xhprof 通用采集脚本 inject.php

# /code/php-xhprof/testcli/inject.php
$xhprof_root = realpath(dirname(__file__) . '/..');
include_once $xhprof_root . "/xhprof_lib/utils/xhprof_lib.php";
include_once $xhprof_root . "/xhprof_lib/utils/xhprof_runs.php";
xhprof_enable(xhprof_flags_no_builtins  xhprof_flags_cpu  xhprof_flags_memory);
// 注册一个函数,当程序执行结束的时候去执行它。
register_shutdown_function(function () {
    // stop profiler
    $xhprof_data = xhprof_disable();
    // 冲刷
    if (function_exists('fastcgi_finish_request')) {
        fastcgi_finish_request();
    }
    // 生成文件
    $xhprof_runs = new xhprofruns_default();
    $xhprof_runs->save_run($xhprof_data, "xhprof_testcli_inject");
});
  • 在执行任意 php 脚本前,进行注入采集脚本,修改 php.ini 配置,设置 auto_prepend_file ,然后重启 php

这样所有的 php 脚本文件执行都会自动注入 inject.php 采集文件,非常方便,无需入侵真正的 php 业务代码;

[root@centos7 php-xhprof]# vim /php/php73/lib/php.ini 
; automatically add files before php document.
; http://php.net/auto-prepend-file
; auto_prepend_file =
auto_prepend_file=/code/php-xhprof/testcli/inject.php

3.3 在 php-fpm 中使用 xhprof 进行性能分析

3.3.1 分析特定域名的 web 请求

还是利用之前的 xhprof 通用采集脚本 inject.php ,可以创建一个新的 /code/php-xhprof/testfpm/inject.php

  • 针对某个站点 利用 fastcgi_param 指令设置 auto_prepend_file
    • 问题:由于 php-fpm 进程可能会复用,也就是多个网站用到同一个 php-fpm worker 进程来处理,这种情况就有可能收集到其他网站的请求
    • 解决:可以通过入侵方式,将代码写入到网站的入口文件,来进行收集数据;
# 追加 配置
# fastcgi_param php_value "auto_prepend_file=/code/php-xhprof/testfpm/inject.php";
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param script_filename $document_root$fastcgi_script_name;
        fastcgi_param server_software nginx;
        fastcgi_param php_value "auto_prepend_file=/code/php-xhprof/testfpm/inject.php";
        include fastcgi.conf;
    }

4、web-ui

4.1 使用 xhprof 自带页面进行性能数据的可视化

4.1.1 xhprof web ui 基本使用

xhprof web ui

可以看到采集的各种请求

  • 点击某个 function name 查看 父子函数的数据对比
    • 可以进入查看 父函数(current function) 和 子函数(child functions) 的数据采集
  • 点击 view callgraph
    • 可以进入查看 函数的调用链,并且根据颜色可以看到哪个函数耗时最大

4.1.2 使用 diff report 对比两次请求采集的数据

tips 使用参数 run1 run2 分别指向两次请求的 run_id ,另外可以点击页面的 invert diff report 来反转两次请求的 run_id

  • 请求 a
function test() {
    $result = 0;
    for ($i=1; $i <= 10000; $i) { 
        $result = $i;
    }
    return $result;
}
  • 请求 b
function test() {
    return 10000 * (110000) / 2;
}

请求b 相比 请求a 可以看到 cpu 和 内存 都大幅度降低;

可以看到函数调用耗时之差,以及调用次数之差

4.1.3 查看汇总请求

tips 使用参数 run=xxx,yyy,zzz 可以汇总多次请求

4.2 使用第三方工具进行性能数据的可视化

4.2.1 perftools/php-profilerperftools/xhgui 的组合拳,瞬间搭建专属的性能分析平台

前情提要

  • 性能分析利器 xhprof
    • php 安装此扩展
  • 通用采集分析器 profiler
    • perftools/php-profiler
    • 支持多种性能分析的扩展;类似一个通用的黑盒,使用此组件,然后选择响应的 性能采集扩展即可
    • xhprof 对应的就是 类 perftools/php-profiler/src/profilers/xhprof.php
    • 支持采集数据的持久化;
  • 性能可视化分析ui xhgui
    • perftools/xhgui
    • 将数据持久化到 mongodb

整体流程就是 project => php-profiler => xhprof => xhgui

快速起一个 web 项目

可以找任意框架,或者你当前的项目,这里只是为了演示,用了这个仓库 。

[root@centos7 php-xhprof]# pwd
/code/php-xhprof
# 克隆项目
[root@centos7 php-xhprof]# git clone https://github.com/tacks9/php-framework-by-composer pfc
[root@centos7 php-xhprof]# ls pfc/
app  bootstrap.php  composer.json  composer.lock  composer.phar  config  data  public  readme.md  services  vendor
# 配置 nginx
[root@centos7 php-xhprof]# vim /etc/nginx/conf/pfc.conf
server
{
    listen 80;
    server_name pfc.tacks.com;
    index index.html index.htm index.php index.shtml index.shtm;
    root /code/php-xhprof/pfc/public;
    access_log /logs/tacks/pfc.tacks.com-access.log;
    error_log /logs/tacks/pfc.tacks.com-error.log;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param script_filename $document_root$fastcgi_script_name;
        fastcgi_param server_software nginx;
        include fastcgi_params;
    }
}
# 重启 nginx
[root@centos7 php-xhprof]# systemctl restart nginx
# 设置 hosts
[root@centos7 php-xhprof]# vim /etc/hosts
127.0.0.1 pfc.tacks.com
# 模拟请求
[root@centos7 php-xhprof]# curl http://pfc.tacks.com/home/echotest
<h1> 控制器、方法  home/echotest </h1>

在你的项目引入

[root@centos7 pfc]# pwd
/code/php-xhprof/pfc
# composer 引入 perftools/php-profiler
[root@centos7 pfc]# composer require perftools/php-profiler
# 增加 profiler.php 探测器启动文件
[root@centos7 pfc]# touch config/profiler.php 
# 项目入口文件引入 profiler.php
[root@centos7 pfc]# vim bootstrap.php 
# 在自动加载器后面
// 【探测器】
require base_path.'/config/profiler.php';
  • 探测器脚本 config/profiler.php
    • 配置 profiler 使用的扩展为 xhprof,因为本文主打就是 xhprof ,当然如果你如果安装类似其他的扩展如 tideways_xhprof ,可以自己尝试
    • 配置数据存储方式 save.handler
      • 主打通过 saver_stack 的方式,可以将采集数据以多种方式存储
      • 接口上传 save.handler.upload
        • 当然你可能会疑惑这个接口哪里来,当时看文档的时候愣是不知道哪里来的接口,这就需要组合拳的另一套 perftools/xhgui 工具
      • 文件存储 save.handler.file
        • 默认以 json 的方式存储到 /tmp/xhgui.data.jsonl
// /code/php-xhprof/pfc/config/profiler.php
<?php
/**
 * bootstrap for php-profiler. copy and customize this file,
 * include this file inside some bootstrapper or other "early central point in execution"
 *
 * documentation:
 * - https://github.com/perftools/php-profiler#create-profiler
 * - https://github.com/perftools/php-profiler#config
 */
use xhgui\profiler\profiler;
use xhgui\profiler\profilingflags;
// require __dir__ . '/../vendor/perftools/php-profiler/autoload.php';
try {
    $config = array(
        // 选择性能分析器 xhprof 扩展
        'profiler' => profiler::profiler_xhprof,
        // 配置要捕获的分析数据
        'profiler.flags' => array(
            profilingflags::cpu,
            profilingflags::memory,
            profilingflags::no_builtins,
            profilingflags::no_spans,
        ),
        // 采集数据的保存方式
        'save.handler' => profiler::saver_stack,
        // 存储数据的接口
        // https://github.com/perftools/php-profiler#upload-saver
        'save.handler.upload' => array(
            'url' => 'http://xhgui.tacks.com/run/import',
            // 接口超时时间
            'timeout' => 3,
            // xhgui 的  upload.token
            'token' => 'token',
        ),
        // 存储数据的文件
        // https://github.com/perftools/php-profiler#file-saver
        'save.handler.file' => array(
            'filename' => '/tmp/xhgui.data.jsonl',
        ),
        // 采用堆栈的方式存储采集数据
        // https://github.com/perftools/php-profiler#stack-saver
        'save.handler.stack' => array(
            'savers' => array(
                profiler::saver_upload,
                profiler::saver_file,
            ),
            // 如果设置 true 就是全部存储,如果false,就按照顺序不成功就用下一个保存方式
            'saveall' => false,
        ),
        // 采用mongodb存储采集数据(作者不推荐直接存储到这里)
        // https://github.com/perftools/php-profiler#mongodb-saver
        'save.handler.mongodb' => array(
            'dsn' => 'mongodb://127.0.0.1:27017',
            'database' => 'xhprof',
            // allows you to pass additional options like replicaset to mongoclient.
            // 'username', 'password' and 'db' (where the user is added)
            'options' => array(),
            // allows you to pass driver options like ca_file to mongoclient
            'driveroptions' => array(),
        ),
        // environment variables to exclude from profiling data
        'profiler.exclude-env' => array(),
        'profiler.options' => array(),
        // 探测器采集(可以保存一定比例的请求,而非全部)
        // profile 1 in 100 requests.
        // you can return true to profile every request.
        'profiler.enable' => function () {
            if ($_server['server_name'] == 'pfc.tacks.com') {
                return true;
                // 100%采样,默认为1%
                return rand(1, 100) === 42;
            } else {
                return false;
            }
        },
        // 请求 url 简化
        'profiler.simple_url' => function ($url) {
            return preg_replace('/=\d /', '', $url);
        },
        // 请求 url 替换,移除敏感信息,例如 token query
        'profiler.replace_url' => function ($url) {
            return str_replace('token', '', $url);
        },
    );
    // 加载配置
    $profiler = new profiler($config);
    // 启动探测器
    $profiler->start();
} catch (exception $e) {
    error_log($e->getmessage());
}

你的php需要mongodb支持

[root@centos7 php-xhprof]# php --ri mongodb
mongodb
mongodb support => enabled
mongodb extension version => 1.15.2
mongodb extension stability => stable
libbson bundled version => 1.23.3
libmongoc bundled version => 1.23.3
libmongoc ssl => enabled
libmongoc ssl library => openssl
libmongoc crypto => enabled
libmongoc crypto library => libcrypto
libmongoc crypto system profile => disabled
libmongoc sasl => enabled
libmongoc icu => disabled
libmongoc compression => enabled
libmongoc compression snappy => disabled
libmongoc compression zlib => enabled
libmongoc compression zstd => disabled
libmongocrypt bundled version => 1.5.2
libmongocrypt crypto => enabled
libmongocrypt crypto library => libcrypto
crypt_shared library version => unknown
directive => local value => master value
mongodb.debug => no value => no value

采集数据持久化需要一个 mongodb

[root@centos7 php-xhprof]# ps -ef | grep mongo | grep -v "grep"
root      6666     1  1 may11 ?        01:30:17 /usr/bin/mongod --dbpath=/mongodb/data -f /etc/mongod.conf
[root@centos7 php-xhprof]# netstat -ntlp | grep mongod
tcp        0      0 0.0.0.0:27017           0.0.0.0:*               listen      6666/mongod 

启动一个

[root@centos7 php-xhprof]# pwd
/code/php-xhprof
# 克隆项目
[root@centos7 php-xhprof]# git clone https://github.com/perftools/xhgui
# 配置 nginx
[root@centos7 php-xhprof]# vim /etc/nginx/conf/xhgui.conf
server
{
    listen 80;
    server_name xhgui.tacks.com;
    index index.html index.htm index.php index.shtml index.shtm;
    root /code/php-xhprof/xhgui/webroot;
    access_log /logs/tacks/xhgui.tacks.com-access.log;
    error_log /logs/tacks/xhgui.tacks.com-error.log;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param script_filename $document_root$fastcgi_script_name;
        fastcgi_param server_software nginx;
        include fastcgi_params;
    }
}
# 重启 nginx
[root@centos7 php-xhprof]# systemctl restart nginx
  • 浏览器访问
  • 访问
    • 你会发现 method not allowed ,这个就是我们在 php-profiler 中填写的配置 save.handler.upload,用来上传数据

大功告成,可以请求你的网站,然后使用性能分析xhgui工具

  • 多次请求

  • 点击 method 列,例如 某一行的 get
  • 点击 jump to functions
  • 点击 view callgraph,查看本次请求的方法调用图
  • 点击 compare this run,对比两次请求

4.2.2 xhgui 的汉化版 laynefyc/xhgui-branch ,更贴合国人使用习惯

    • 更多说明,请看 readme

前情提要

  • 性能分析利器 xhprof
    • php 安装此扩展
  • 通用采集分析器 xhgui-chinese
    • 支持采集数据的持久化,默认存储 mongodb
  • 性能可视化分析ui xhgui-chinesewebroot
    • 将数据可视化展示,并且进行汉化,看起来直观一些

整体流程就是 project => xhgui-chinese => mongodb => webroot

快速起一个 web 项目

可以找任意框架,或者你当前的项目,这里只是为了演示,依然用了这个仓库 。

  • 初始化一个新的 web 项目即可,比如访问的 pfc.tacks.com ,剩下的就不演示了。
[root@centos7 php-xhprof]# git clone https://github.com/tacks9/php-framework-by-composer pfc
[root@centos7 pfc]# pwd
/code/php-xhprof/pfc
[root@centos7 pfc]# ls
app  bootstrap.php  composer.json  composer.lock  composer.phar  config  data  public  readme.md  services  vendor

部署 xhgui 汉化版

# 克隆项目
[root@centos7 php-xhprof]# git clone https://github.com/laynefyc/xhgui-branch xhgui-chinese
[root@centos7 xhgui-chinese]# pwd
/code/php-xhprof/xhgui-chinese
# composer 安装依赖
[root@centos7 xhgui-chinese]# composer install
# 设置缓存目录
[root@centos7 xhgui-chinese]# chmod -r 777 cache
[root@centos7 xhgui-chinese]# ls
cache  code_of_conduct.md  composer.json  composer.lock  config  _config.yml  external  install.php  license  phpunit.xml  readme.md  src  tests  vendor  webroot
# 配置 nginx
[root@centos7 xhgui-chinese]# vim /etc/nginx/conf/xhgui-chinese.conf
server
{
    listen 80;
    server_name xhgui-chinese.tacks.com;
    index index.html index.htm index.php index.shtml index.shtm;
    root /code/php-xhprof/xhgui-chinese/webroot;
    access_log /logs/tacks/xhgui-chinese.tacks.com-access.log;
    error_log /logs/tacks/xhgui-chinese.tacks.com-error.log;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param script_filename $document_root$fastcgi_script_name;
        fastcgi_param server_software nginx;
        include fastcgi_params;
    }
}
# 重启 nginx
[root@centos7 xhgui-chinese]# systemctl restart nginx
  • 浏览器访问

设置 xhgui 汉化版的配置文件

# 自定义配置
[root@centos7 xhgui-chinese]# cp conf/config.default.php conf/config.php
[root@centos7 xhgui-chinese]# vim conf/config.php
  • conf/config.php 配置如下
    • 主要是对 profiler.enable 进行设置,只接收来自设定的域名请求
    • extension 扩展,依然采用 xhprof
    • save.handler 采集数据,使用 mongodb ,所以请先安装 php 的 mongodb 扩展
    • db.host 需要 mongodb 的服务端,可以本地启动一个,账号密码啥的可以在 db.options 设置在数组中
    • 数据库,默认采用 xhprof,当然可以重设一下,比如 xhprof-xhgui-chinese

return array(
    'debug' => false,
    'mode' => 'development',
    /*
     * support extension: uprofiler, tideways_xhprof, tideways, xhprof
     * default: xhprof
     */
    'extension' => 'xhprof',
    // can be either mongodb or file.
    /*
    'save.handler' => 'file',
    'save.handler.filename' => dirname(__dir__) . '/cache/' . 'xhgui.data.' . microtime(true) . '_' . substr(md5($url), 0, 6),
    */
    'save.handler' => 'mongodb',
    // needed for file save handler. beware of file locking. you can adujst this file path
    // to reduce locking problems (eg uniqid, time ...)
    //'save.handler.filename' => __dir__.'/../data/xhgui_'.date('ymd').'.dat',
    'db.host' => 'mongodb://127.0.0.1:27017',
    'db.db' => 'xhprof-xhgui-chinese',
    // allows you to pass additional options like replicaset to mongoclient.
    // 'username', 'password' and 'db' (where the user is added)
    'db.options' => array(),
    'templates.path' => dirname(__dir__) . '/src/templates',
    'date.format' => 'y-m-d h:i:s',
    'detail.count' => 6,
    'page.limit' => 25,
    // profile 1 in 100 requests.
    // you can return true to profile every request.
    'profiler.enable' => function () {
        // return true;//rand(1, 100) === 42;
        if ($_server['server_name'] == 'pfc.tacks.com') {
            return true;
            // 100%采样,默认为1%
            return rand(1, 100) === 42;
        } else {
            return false;
        }
    },
    'profiler.simple_url' => function ($url) {
        return preg_replace('/\=\d /', '', $url);
    },
    'profiler.filter_path' => array(
        //'/home/admin/www/xhgui/webroot','f:/phppro'
    )
);

mongodb 优化索引

这里用我本地测试的 mongodb 进行设置,如果你没有 mongodb 请先移步寻找如何安装。

至于 db 名字,看你在项目中如何配置的,如果为 xhprof-xhgui-chineseuse xhprof-xhgui-chinese ,默认的 db 名字为 xhprof

[root@centos7 pfc]# mongo
mongodb shell version v4.2.23
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiservicename=mongodb
implicit session: session { "id" : uuid("7b8bf1d3-507b-4c2f-aa18-c1c4615b515f") }
mongodb server version: 4.2.23
> use xhprof-xhgui-chinese
> db.results.ensureindex( { 'meta.server.request_time' : -1 } )
> db.results.ensureindex( { 'profile.main().wt' : -1 } )
> db.results.ensureindex( { 'profile.main().mu' : -1 } )
> db.results.ensureindex( { 'profile.main().cpu' : -1 } )
> db.results.ensureindex( { 'meta.url' : 1 } )

设置 xhgui 需要监控的项目

  • header.php 需要引入的文件
[root@centos7 xhgui-chinese]# ls external/header.php 
external/header.php
[root@centos7 xhgui-chinese]# ls /code/php-xhprof/xhgui-chinese/external/header.php 
/code/php-xhprof/xhgui-chinese/external/header.php 
  • nginx 配置,利用 fastcgi_param 设置 auto_prepend_file
# 配置 nginx
[root@centos7 php-xhprof]# vim /etc/nginx/conf/pfc.conf
server
{
    listen 80;
    server_name pfc.tacks.com;
    index index.html index.htm index.php index.shtml index.shtm;
    root /code/php-xhprof/pfc/public;
    access_log /logs/tacks/pfc.tacks.com-access.log;
    error_log /logs/tacks/pfc.tacks.com-error.log;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param script_filename $document_root$fastcgi_script_name;
        fastcgi_param server_software nginx;
        fastcgi_param php_value "auto_prepend_file=/code/php-xhprof/xhgui-chinese/external/header.php";
        include fastcgi_params;
    }
}
# 重启 nginx
[root@centos7 php-xhprof]# systemctl restart nginx

大功告成,可以请求你的网站,然后使用性能分析xhgui-chinese工具

  • 多次请求

  • 点击 “方法” 列,例如 某一行的 get
  • 点击 “跳转函数” 按钮
  • 点击 “查看调用图” 按钮
  • 点击 “查看火焰图” 按钮
  • 点击 “对比这次运行” 按钮
本作品采用《cc 协议》,转载必须注明作者和本文链接
明天我们吃什么 悲哀藏在现实中 tacks
本帖由系统于 10个月前 自动加精
讨论数量: 2

太好了,非常需要这个

1年前

得侵入式代码,感觉不大方便

9个月前

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