PHP 性能分析利器 —— 搭建 xhprof 分析环境到实战!

86 阅读4分钟

着业务复杂度的增加,PHP 的性能问题越来越明显。为了提升 PHP 的性能,开发人员通常会利用各种性能分析工具。

xhprof 是优秀的性能分析 PHP 扩展,它能收集程序运行时函数调用信息和内存使用情况,帮助开发者发现性能瓶颈。

引用官方的描述,我做了中文翻译:

XHProf 是 PHP 的函数级分层分析器,具有一个简单的基于 HTML 的导航界面。

原始数据收集组件是用 C 语言实现的(作为 PHP 扩展),报告/UI 层全部使用 PHP。

它能够报告函数级别的非独占和独占实际时间、内存使用情况、CPU 时间和每个函数的调用次数。

此外,它还支持比较两次运行(分层 DIFF 报告)或聚合多次运行的结果。

本文将详细介绍如何使用 xhprof 对 PHP 进行性能优化,包括 xhprof 的安装与配置、使用方法、性能分析指标以及在实际项目中的应用。

安装和配置

xhprof 支持 PHP7.2 以上的版本,可以在以下地址下载(我使用的是 2.3.10 版本):

下载后解压,进入目录编译安装:

cd xhprof/extension/
/path/to/php7/bin/phpize
./configure --with-php-config=/path/to/php7/bin/php-config
make && sudo make install

然后修改php.ini​文件,文件末尾添加以下内容:

[xhprof]
extension=xhprof.so
xhprof.output_dir=/tmp/xhprof

不要忘记重启您的 php-fpm​ 让扩展生效。如果您不确定是否安装,可以执行以下命令确认:

php -m
php --ri xhprof

准备探针项目

我们可以新建 xhprof.test.com​ 工程,加入 xhprof_html​ 和 xhprof_lib​ 目录,并新增 php72.php​ 文件:

xhprof/xhprof_html/... PS: 来自源码包
xhprof/xhprof_lib/... PS: 来自源码包
xhprof/php72.php

探针文件 php72.php(可根据实际需要修改):

<?php

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();
    }
    include_once dirname(__FILE__) . '/xhprof_lib/utils/xhprof_lib.php';
    include_once dirname(__FILE__) . '/xhprof_lib/utils/xhprof_runs.php';
    $xhprof_runs = new \XHProfRuns_Default();
    $xhprof_runs->save_run($xhprof_data, 'xhprof');
});

部署可视化工具

探针准备好了之后,我们继续部署可视化工具。

xhprof 提供了一个开箱即用的 Web UI——没错,就是源码包下的 xhprof_html 目录。

它的原理是在引入上述的探针文件 php72.php 后,运行我们的代码,扩展会写入性能分析数据到 php.ini 里面配置的 output_dir 目录(/tmp/xhprof)中。

此时 Web UI 读取并解析该目录,调用 graphviz 项目生成图片,渲染展示到浏览器上。

我们需要将 xhprof.test.com​ 和 待性能分析的项目一起部署。

推荐在开发或者测试环境部署,不建议生产环境使用,避免影响到生产环境的业务。

我基于 docker-compose 搭建了一套开发测试环境, 集成了 nginx + PHP7 环境,而 xhprof UI 的运行,需要提前安装 graphviz 项目,这里以 CentOS 为例:

yum install graphviz -y

配置好 nginx 的 vhost,root 指向 xhprof_html 目录,我们就可以开始定位问题了!

如何定位问题

假设我们现在要定位 Laravel 项目的控制器某个函数的性能问题(接口非常慢)!

如某项目的某个接口,有时候要 几十秒​ 才返回,单纯看代码(大几千行)非常难定位原因!

这个时候我们引入上面的项目文件:

class TestController extends Controller
{
    // ...
    public function getInfo(Request $request)
    {
        // 此处引入一行代码即可
        require_once '/path/to/xhprof.test.com/xhprof/php72x.php';

        // ...
        // 业务逻辑巴拉巴拉
    }

    // ...
}

访问 xhprof.test.com 我们可以得到这个图:

image-20240923230020-f1nz9jn.png 点击 [View Full Callgraph]​ 可以获取调用图,图中可以看到,

接口在最后请求了 App\Service\DataSystem\xxxxx::yy​ 函数,

最后在 curl_exec​ 耗时 40s​ !!!

image-20240926185952-qrhgl80.png

查询函数调用的上下文,第一眼就可以定位出是获取某数据耗时很长(这里打了马赛克,实际项目会展示完整的函数名称)!

image-20240926190101-qp5mo22.png 翻查代码后发现,接口依赖的下游(curl_exec 耗时 40s)确实存在问题,修复后就恢复正常了!

总结

总的来说,xhprof 是一个强大的 PHP 性能分析扩展,通过它,我们可以快速定位并解决 PHP 程序中的性能问题。

它不仅提供了详尽的性能数据,还通过可视化工具帮助我们直观地理解程序的运行状况。在实际应用中,xhprof 可以帮助我们识别出代码中的性能瓶颈,从而进行针对性的优化。

扩展阅读

对于想要深入了解 xhprof 的用户,可以阅读官方文档,了解更多关于 xhprof 的高级特性和最佳实践。

此外,还可以探索其他 PHP 性能分析工具,如 xhgui + tideways,它们也提供了更加美观大方的 UI 和更强大的性能分析功能!

通过结合使用不同的工具,我们可以更全面地了解应用程序的性能状况,并采取有效的优化措施。