Linux系统下使用XHProf和XHGui分析PHP运行性能


Posted in PHP onDecember 08, 2015

什么是性能分析?
性能分析是衡量应用程序在代码级别的相对性能。性能分析将捕捉的事件包括:CPU的使用,内存的使用,函数的调用时长和次数,以及调用图。性能分析的行为也会影响应用性能。
什么时候应该进行性能分析?
在考虑是否进行性能分析时,你首先要想:应用是否存在性能问题?如果有,你要进一步考虑:这个问题有多大?

如果你不这样做,将会陷入一个陷阱——过早优化,这可能会浪费你的时间。

为了评断应用是否存在性能问题,你应该确定性能目标。例如,100 个并发用户的响应时间小于 1s 。然后,你需要进行基准测试,看是否达到这个目标。一个常见的错误是,在开发环境进行基准测试。事实上,你必须在生产环境进行基准测试。(实际生产环境或模拟的生产环境,后者很容易在 SaaS 实现。
用于基准测试的产品很多,包括 ab,siege 和 JMeter。我个人比较喜欢 JMeter 的功能集,但 ab 和 siege 更加易用。

一旦你确定应用存在性能问题,就需要分析其性能,实施改进,然后再一次进行基准测试,查看问题是否解决。每一次变更之后,你都该进行基准测试查看效果。如果你做了很多变更,却发现应用性能有所下降,你就无法确定具体是哪一次变更导致了这个问题。

下图是我定义的性能生命周期:

Linux系统下使用XHProf和XHGui分析PHP运行性能

性能下降的一般原因
导致性能下降的一般原因中,有些相当出人意料。即便是像 PHP 这样的高级语言,代码的好坏也很少是问题的根源。在当今的硬件配置条件下,CPU 很少是性能限制的原因。常见的原因反而是:

数据存储

  • PostgreSQL
  • MySQL
  • Oracle
  • MSSQL
  • MongoDB
  • Riak
  • Cassandra
  • Memcache
  • CouchDB
  • Redis

外部资源

  • APIs
  • 文件系统
  • 网络接口
  • 外部流程
  • 糟糕的代码

选择哪一种性能分析器?
在 PHP 世界里,有两个截然不同的的性能分析器——主动和被动。

主动 VS 被动性能分析
主动分析器在开发过程中使用,由开发人员启用。主动分析器收集的信息比被动分析器多,对性能的影响更大。通常,主动分析器不能用在生产环境中。XDebug 就是一种主动分析器。

因为无法在生产环境中使用主动分析器,Facebook 推出了一个被动分析器——XHProf。XHProf 是为了在生产环境中使用而打造的。它对性能的影响最小,同时收集足够的信息用于诊断性能问题。XHProf 和 OneAPM 都是被动分析器。

通常,XDebug 收集的额外信息对于一般的性能问题分析并不必要。这意味着,被动分析器是用于不间断性能分析的更佳选择,即使是在开发环境中。

XHProf + XHGui
XHProf 由 Facebook 开发的,包含一个基本的用户界面用于查看性能数据。此外,Paul Reinheimer 开发了 XHGui 和一个增强的用户界面(UI)用于查看、比较和分析性能数据。

安装
安装 XHProf
XHProf 可通过 PECL 安装,步骤如下:

$ pecl install xhprof-beta

该 pecl 命令将尝试自动更新你的 php.ini 设置。pecl 尝试更新的文件可以使用以下命令找到:

$ pecl config-get php_ini

它会在指定的文件(如果有的话)顶部增加新的配置行。你可能想把他们移到一个更合适的位置。

一旦你编译了该扩展程序,您必须启用它。为此,您需要在 PHP INI 文件添加以下代码:

[xhprof]
extension=xhprof.so

之后,结合 XHGui 就能轻松地执行性能分析与检查。

安装 XHGui
安装 XHGui,必须直接从 git 获取。该项目可以在 github 上找到,地址为:https://github.com/perftools/xhgui

XHGui 要求:

  • PHP 5.3+
  • ext/mongo
  • composer
  • MongoDB (若只需要收集数据,则可选可不选;若需要数据分析,则为必选)

首先,克隆项目到任意位置。在基于 Debian 的 Linux 系统(例如 Ubuntu 等等),可能是 /var/www。在 Mac OS X 系统,可能是 /Library/WebServer/Documents。

$ cd /var/www
$ git clone https://github.com/perftools/xhgui.git
$ cd xhgui
$ php install.php

最后一个命令是运行 composer 以安装依赖并检查 XHGui 缓存目录的权限。如果失败,你可以手动运行 composer install。

下一步,你可能需要创建配置文件。这一步很容易实现,可以使用在 /path/to/XHGui/config/config.default.php 下的默认配置文件。

如果你在本地运行 MongoDB,没有身份验证,则可能不需要这样做。因为它将回退为默认值。而在多服务器环境中,你会需要一个所有服务器都能进行存储的远程 MongoDB 服务器,并进行恰当的配置。

为提高 MongoDB 的性能,你可以运行以下指令以添加索引:

$ mongo
> use xhprof
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 } )

其他配置
如果你不想在生产环境中安装 mongo ,或无法让 Web 服务器访问 mongo 服务器,您可以将性能分析数据保存在磁盘中,再导入到本地 MongoDB 供以后分析。

为此,请在 config.php 中进行以下修改:

<?php 
'save.handler' = 'file', 
'save.handler.filename' => '/path/to/xhgui/xhprof-' .uniqid("", true). '.dat', 
?>

改变文件中的 save.handler,然后取消批注 save.handler.filename ,为其赋一个恰当的值。

注意:默认每天只保存一个分析文件。

一旦分析数据的准备就绪,你就可以使用 XHGui 附带的脚本导入之:

$php /path/to/xhgui/external/import.php /path/to/file.dat

在此之后的步骤都相同。

运行 XHGui
XHGui 是以 PHP 为基础的 Web 应用程序,你可以以 /path/to/xhgui/webroot 为根文件,设置一个标准的虚拟主机。

或者,你可以简单地使用 PHP 5.4+ cli-server 例如:

$ cd /path/to/xhgui
$ php -S 0:8080 -t webroot/
这将使 XHGui 在所有网络接口都可通过 8080 端口进行通信。

运行性能分析器
运行分析器时,你需要在待分析的所有页面包含 external/header.php 脚本。为此,你可以在 PHP ini 文件设置 auto_prepend_file 。你既可以直接在公共 INI 文件进行设置,也可以限制到单一的虚拟主机。

对于 Apache 服务器,添加以下代码:

php_admin_value auto_prepend_file "/path/to/xhgui/external/header.php"

对于 Nginx 服务器,在服务器配置中添加以下代码:

fastcgi_param PHP_VALUE "auto_prepend_file=/path/to/xhgui/external/header.php";

如果您使用 PHP 5.4+ cli-server(PHP -S),则必须通过命令行标记进行设置:

$ php -S 0:8080 -dauto_prepend_file=/path/to/xhgui/external/header.php

默认情况下,分析器运行时只分析(大约) 1% 的请求。这是由以下 external/header.php 代码控制的:

<?php 
if (rand(0, 100) !== 42) { 
  return;
}
?>

如果你想分析每一个请求(例如,在开发阶段),你可以将这段代码注释掉。如果你想让分析 10% 的请求,你可以做如下改动:

<?php
if (rand(0, 10) !== 4) {
  return;
}
?>

这允许你对一小部分用户请求进行分析,而不过多影响单个用户或太多用户。

如果你想在性能分析时进行手动控制,你可以这样做:

<?php 
if (!isset($_REQUEST['A9v3XUsnKX3aEiNsUDZzV']) && !isset($_COOKIE['A9v3XUsnKX3aEiNsUDZzV'])) { 
 return;
} else {
 // Remove trace of the special variable from REQUEST_URI
 $_SERVER['REQUEST_URI'] = str_replace(array('?A9v3XUsnKX3aEiNsUDZzV', '&A9v3XUsnKX3aEiNsUDZzV'), '', $_SERVER['REQUEST_URI']);
 setcookie('A9v3XUsnKX3aEiNsUDZzV', 1);
}
if (isset($_REQUEST['no-A9v3XUsnKX3aEiNsUDZzV'])) { 
 setcookie('A9v3XUsnKX3aEiNsUDZzV', 0, time() - 86400);
 return;
}
?>

这段代码会检查一个随机命名的 GET/POST/COOKIE 变量(在此例中为:A9v3XUsnKX3aEiNsUDZzV),同时创建一个同名的 Cookie ,用于分析该请求的整个过程,例如:表单提交后的重定向,Ajax 请求等等。

此外,它允许一个名为 no-A9v3XUsnKX3aEiNsUDZzV 的 GET/POST 变量来删除 Cookie ,停止分析。

当然,我们欢迎大家尝试使用 OneAPM 来为您的 PHP 和 Java 应用做免费的性能分析。OneAPM 独有的探针能够深入到所有 PHP 和 Java 应用内部完成应用性能管理和监控,包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。 OneAPM 可以追溯到性能表现差的 SQL 语句 Traces 记录、性能表现差的第三方 API、Web 服务、Cache 等等。

PHP 相关文章推荐
Dedecms常用函数解析
Feb 01 PHP
三个类概括PHP的五种设计模式
Sep 05 PHP
探讨PHP中this,self,parent的区别详解
Jun 08 PHP
浅析php学习的路线图
Jul 10 PHP
thinkPHP的表达式查询用法详解
Sep 14 PHP
PHP mysqli_free_result()与mysqli_fetch_array()函数详解
Sep 21 PHP
php如何修改SESSION的生存存储时间的实例代码
Jul 05 PHP
php mysql PDO 查询操作的实例详解
Sep 23 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
Feb 10 PHP
Yii使用EasyWechat实现小程序获取用户的openID的方法
Apr 29 PHP
PHP dirname(__FILE__)原理及用法解析
Oct 28 PHP
php引用传递
Apr 01 PHP
thinkPHP中create方法与令牌验证实例浅析
Dec 08 #PHP
详解PHP的Yii框架中日志的相关配置及使用
Dec 08 #PHP
UPUPW 更新 64 位 Apache 系列 PHP 7.0 正式版
Dec 08 #PHP
学习php设计模式 php实现模板方法模式
Dec 08 #PHP
PHP7正式版测试,性能惊艳!
Dec 08 #PHP
学习php设计模式 php实现命令模式(command)
Dec 08 #PHP
学习php设计模式 php实现合成模式(composite)
Dec 08 #PHP
You might like
PHP伪静态页面函数附使用方法
2008/06/20 PHP
使用PHP curl模拟浏览器抓取网站信息
2013/10/28 PHP
利用phpExcel实现Excel数据的导入导出(全步骤详细解析)
2013/11/26 PHP
PHP中source #N问题的解决方法
2014/01/27 PHP
详解Yii2高级版引入bootstrap.js的一个办法
2017/03/21 PHP
Thinkphp 框架扩展之应用模式实现方法分析
2020/04/27 PHP
Javascript-Mozilla和IE中的一个函数直接量的问题
2007/01/09 Javascript
JavaScript中“+=”的应用
2007/02/02 Javascript
JavaScript DOM学习第四章 getElementByTagNames
2010/02/19 Javascript
jquery判断浏览器类型的代码
2012/11/05 Javascript
HTML上传控件取消选择
2013/03/06 Javascript
浅谈JavaScript字符串拼接
2015/06/25 Javascript
一个极为简单的requirejs实现方法
2016/10/20 Javascript
JS中parseInt()和map()用法分析
2016/12/16 Javascript
javascript操作cookie
2017/01/17 Javascript
前端分页功能的实现以及原理(jQuery)
2017/01/22 Javascript
Django使用多数据库的方法
2017/09/06 Javascript
实例讲解javascript实现异步图片上传方法
2017/12/05 Javascript
解决mpvue + vuex 开发微信小程序vuex辅助函数mapState、mapGetters不可用问题
2018/08/03 Javascript
微信小程序实现笑脸评分功能
2018/11/03 Javascript
微信小程序获取用户信息并保存登录状态详解
2019/05/10 Javascript
详细分析vue表单数据的绑定
2020/07/20 Javascript
解决ant Design中this.props.form.validateFields未执行的问题
2020/10/27 Javascript
[01:00:14]DOTA2-DPC中国联赛 正赛 Ehome vs Elephant BO3 第二场 2月28日
2021/03/11 DOTA
对python中xlsx,csv以及json文件的相互转化方法详解
2018/12/25 Python
Python散点图与折线图绘制过程解析
2019/11/30 Python
Python numpy多维数组实现原理详解
2020/03/10 Python
HTML5中5个简单实用的API(第二篇,含全屏、可见性、拍照、预加载、电池状态)
2014/05/07 HTML / CSS
HTML5 直播疯狂点赞动画实现代码 附源码
2020/04/14 HTML / CSS
俄罗斯厨房产品购物网站:COOK HOUSE
2021/03/15 全球购物
日本亚马逊官方网站:Amazon.co.jp
2020/04/14 全球购物
计算机学生的自我评价分享
2014/02/18 职场文书
公司新人试用期自我评价
2014/09/17 职场文书
党的群众路线教育实践活动学习计划
2014/11/03 职场文书
体育教师教学随笔
2015/08/15 职场文书
从贫穷到富有,是知识技能和学习力的差别
2019/08/20 职场文书