EXHPROF是什么?
Exhprof 是一个php性能数据自动化收集及分析平台,其客户端为你提供php代码函数级的性能数据的自动化统计和自动化收集,其服务器端为你提供高效灵活的历史数据存储,和信息聚合分析,通过表格和图像形式展现出来。
Exhprof的优势在于:
• 做到了实时自动化收集php函数级性能数据,客户端使用灵活且成本低,服务器端信息展现形式友好,利于快速准确的定位性能瓶颈
• 做到了轻量级的性能数据统计,对原有程序性能影响较小。你可以在客户端轻松配置统计的信息类型、函数层级,并提供了抽样频率控制。
• 基于xhprof的性能数据统计,功能相比其他统计工具更强大。你不仅可以获取到时间信息,更可以获取到cpu、mem等性能信息
• 信息展现web化,方便且友好,同时还提供了历史版本性能数据diff、多次请求平均性能统计和图像化展示功能,其对性能关键路径标识让你一目了然
• 可以轻松扩展更多采集信息,并进行不同维度的信息聚合分析,比如按照url进行聚合分析。存储系统采用了Nosql作为解决方案,这也使得信息的扩展十分容易。
Exhprof架构图如图1-1所示。
图1-1 exhprof架构图
2 为什么要使用EXHPROF?
• 你是否为定位性能问题耗费过多的时间而头疼呢?
• 你是否还在使用xdebug,而头疼压力下无法进行性能统计或性能统计误差太大呢?
• 你是否想获得压力下真实的系统性能瓶颈,甚至线上环境的实时性能数据呢?
• 你是否还在纠结其他性能统计工具只能得到请求耗时而无法获得请求cpu占用信息呢?
——是的,你已经有足够的理由,使用Exhprof,你将轻松解决这些问题,让你迅速便捷的定位性能瓶颈。 同时,下面的几个理由或许也吸引你:
• 通过历史版本性能数据diff功能,可以清楚的了解到性能的改进点
• 灵活的定制性能统计信息,提供debug模式更加方便用户进行信息查看
你可以通过下表进一步了解我们的调研信息,在进行Exhprof的设计调研中,我们重点对xdebug和xhprof的特点进行了对比分析,见下表
表2-1 exhprof vs xhprof vs xdebug
3 深入了解EXHPROF...
3.1 功能需求说明
1.性能数据的实时采集:包括函数级的性能数据、请求的URL、请求时刻等。
2.性能数据易扩展:可以对用户透明的做到采集数据的增加和减少,不需要在后端进行大量改动。
3.性能数据的采集不会给原有服务带来大量的性能消耗,便于性能测试和生产环境部署
4.支持分布式多机性能数据采集:以便于支持多测试机,多产品线,多模块的性能采集和存储。
5.后端数据可扩展为分布式存储,便于存储和处理大量的历史数据。
6.服务器端包括基本的展现视图:单个请求视图、多个请求平均性能视图、两个请求的性能diff视图,函数性能视图
7.搜索功能:按照函数名精确搜索
8.信息聚合分析功能:按页面类型进行聚合分析,按时间段进行聚合分析
9.自动化数据采集,无需人工干涉。
10.服务器端以web页面展现,界面友好,操作方便。
3.2 系统架构设计
从设计上,Exhprof包括客户端和服务器部分,客户端部分负责性能数据的监控采集,服务器端负责数据的分析和展现。
系统有两种设计方案,区别主要集中在数据分布式采集上。
3.2.1 方案一
• 客户端:包括两部分:客户端脚本和客户端后台服务。
客户端脚本采用php实现,直接嵌入到被监控的php代码中,基于xhprof进行基础的函数级性能采集,然后对收集到的性能数据进行定制、过滤、添加产生最终的性能数据,最后将性能数据dump到本机硬盘存储。 客户端后台服务采用C/C++实现,主要负责数据的分布式采集,采取服务器端统一定时采集的方式,在客户端机器运行一个后台服务,侦听一个端口,提供性能数据的管理服务。服务器端定时向客户端请求获取性能数据。
• 服务器端:
web展现,主要采用php+js实现,php采用Yii框架,js采用jquery框架。 后端存储,性能数据字段不确定的特点非常适合采用nosql实现,具体设计中采用了基于文档的数据库mongodb,在性能和扩展性上都得到了很大的提高。 定期后台服务,需要定期向客户端机器请求获取性能数据,将请求到性能数据存储到后端mongodb中。
3.2.2 方案二
• 客户端:只包括客户端脚本
与方案一的不同在于,在数据的分布式采集上,采用客户端脚本直接将采集数据发送到后端mongodb,性能的采集频率等配置全部在客户端脚本中实现,虽然不便于统一的配置管理,但是在开发效率和用户使用便利性上得到了更大的改善。 在实际实现中,客户端无需在本地磁盘存储性能数据,所有性能数据直接写入到服务器端mongodb中,写入方式可以配置同步写和异步写,同时在后端mongodb采用capped collection来实现,写入性能极高,几乎等同于直接写硬盘。
• 服务器端:
服务器端只是基于mongodb进行数据的分析和展现,而不再向客户端机型数据的收集。 方案二架构请参见图1-1
3.3 设计改进考虑
3.3.1 客户端性能数据监控的性能开销
函数级的性能监控碰到最大的问题是,给原有程序带来的性能开销过大,导致监控数据失真,并且无法应用到性能环境和生产环境,进而无法获取到压力下/线上真实的性能数据。
改进措施的考虑包括以下方面,具体的性能开销评估报告请参考第4节
• 1. 采用xhprof进行基础的函数性能数据统计,xhprof为开源的轻量级性能统计工具
• 2. 对性能采集级别和采集函数进行定制,不同的环境和需求定制不同的监控级别,通过对配置定制监控级别和过滤不必要的函数,使得性能开销进一步降低
• 3. 数据采集时可以开启异步写模式,使得数据的写入速度大大提升
• 4. 后端放弃mysql,而采用nosql,并且采用mongodb的capped collection进行存储,大大提高的数据写入性能。
3.3.2 数据采集方式
分布式数据采集方式有同步采集和异步采集两种,从降低对原有程序影响的角度考虑,采用异步采集方式更好。异步方式有两种实现方案,分别在前面的方案一和方 案二中进行了描述。 其中方案二是我们实现中采用的方式,其异步主要体现在写数据库的异步写上,由于采用了mongodb的capped collection实现,即使同步 写,性能开销也很搞,几乎等同于写硬盘,所以我们默认关闭异步写,以免发生数据写失败时丢失,在性能环境/生产环境中,建议用户开启异步写。
3.3.3 数据存储形式和扩展性
4 使用EXHPROF带来的性能开销
4.1 测试目标
• 给出客户端脚本在性能数据采集过程中对原有系统带来的性能开销
• 评估方式包括:debug模式(单个请求消耗),抽样模式(性能环境采样),异步模式(客户端采样完毕后的数据处理带来的消耗)
• 客户端的性能采集数据包括:默认采集(采集函数级耗时信息), cpu采集(采集函数级cpu占用信息),mem采集(采集函数级mem使用信息)
• 给出部署和配置建议
4.2 DEBUG模式——功能环境
【说明】
• 无采集——不进行性能采集的请求耗时
• 默认采集——对所有函数进行函数级耗时信息采集
• cpu采集——对所有函数进行函数级耗时信息+cpu占用信息采集
• cpu+mem采集——对所有函数进行函数级耗时信息+cpu占用信息+mem占用信息采集
表4-1 debug模式性能评估表
【结论】
DEBUG模式为全功能模式,对请求时延的消耗为84ms,占比为(277-193)/193=44%,考虑到全功能的优势,在线下功能环境建议开启DEBUG模式
4.3 抽样模式——性能环境/生产环境
【场景说明】
• 压力大小:20次/s
• 抽样频率:1/100
• 压力时间:10分钟
表4-2 抽样模式性能评估表
【结论】
抽样模式通过抽样来保证性能数据采集不会对服务造成影响,对于命中抽样的请求,建议关闭cpu采集,只进行默认采集即可。
4.4 异步收集模式——数据存储的消耗
表4-3 异步收集模式性能评估表
4.5 部署和配置建议
4.5.1 功能环境
功能环境使用DEBUG模式即可,DEBUG模式具体配置及特点如下:
• 1.打开所有函数的性能数据收集,不设置过滤函数,对php内置函数也进行收集
• 2.打开请求时间、cpu、mem的数据收集,并且可以检测死循环
• 3.在请求的页面顶部,会输出调试信息,包括到exhprof的入口链接
4.5.2 性能环境/生产环境
性能环境中务必使用抽样模式,同时建议只开始默认采集,抽样的频率的配置原则建议为30s采样一次,及抽样频率=压力大小*30。
5 如何开始使用EXHPROF
5.1 安装xhprof和mongodb扩展
5.1.1 安装xhprof.so
$ wget http://pecl.php.net/get/xhprof-0.9.2.tgz
$ tar xzvf xhprof-0.9.2.tgz
$ cd <xhprof_source_directory>/extension/
$ phpize
$ ./configure --with-php-config=<path to php-config>
$ make
$ make install
$ make test
5.1.2 安装mongo.so
从https://github.com/mongodb/mongo-php-driver下载driver到测试机
$ tar zxvf mongodb-mongodb-php-driver-<commit_id>.tar.gz
$ cd mongodb-mongodb-php-driver-<commit_id>
$ phpize
$ ./configure
$ make
$ make install
5.1.3 更新php.ini
extension_dir ="/home/work/php/ext"
[xhprof]
extension=xhprof.so
[mongo]
extension=mongo.so
5.2 部署客户端脚本
从中控机下载客户端脚本Exhprof-client.tar.gz到测试机,并解压;然后在你想要监控的代码前后require客户端脚本,一般来说,要对整个请求进行监控,在php框架的入口文件index.php的开头和末尾分别加载以上客户端脚本即可。
require_once '/home/work/lib/Exhprof-client/xhprof_start.php';
#Here your code is!!
require_once '/home/work/lib/Exhprof-client/xhprof_stop.php';
5.3 申请空间
你可以通过页面中的"设置->申请空间“来申请后端存储空间。
建议你填写的空间名为你的产品线名或测试机名,申请成功之后,可以在客户端脚本配置中使用该空间名。
注意:如果你使用未经过申请的空间名,系统会自动为你分配后端的空间,自动分配的空间性能相对差一些,但是空间的大小不限,会造成后端数据大小不可控,所以建议通过web端进行固定大小的空间申请。
5.4 配置客户端脚本
至此,你已经部署完毕,可以在url中添加参加prof来即时开启性能监控,监控的概要信息会在监控页面中输出。
如果不想采用默认配置,可以修改客户端脚本的配置文件,进一步对性能函数统计等信息进行配置和定制,配置文件如下:
#后端配置,无需修改
//exhprof webserver.
$XHPROF_SERVER="[WEBURL] ";
//mongodb.
$HOST="[IP:PORT]";
#环境配置,后端使用"ENV_TAG+ENV_TYPE"来进行唯一标识
##0--功能 1--性能
$ENV_TYPE=0;————功能环境的后端存储空间为2G,而性能环境存储空间为25G或更大,一般来说功能满足日常测试需求,如果需要在性能环境或线上环境进行长期数据采集,则需要申请性能环境。
$ENV_TAG="XXX ";————通过web端EXHPROF申请得到的空间TAG
## normal : 不影响原有服务,通过在url中添加参数来开启监控,并在请求页面中输出概要信息供调试
## debug : 每个请求都会进行监控,并且在页面中输出概要信息
## press : 对所有请求进行抽样监控,不在页面中输出调试信息,适用于性能环境
$MODE='normal';
#模式的详细配置信息
#by_url_param : true-通过url中携带参数来开启监控, false-通过抽样频率来开启监控
#is_print_abstart: true-在请求页面中打印概要信息, fase-不打印
#param_name : url参数名,在by_url_param模式中使用
#sample_num : 抽样频率,建议: 30*压力大小,即30s取样一次.
#no_builtins : 是否监控php内部函数性能数据
#cpu_monitor : 是否监控cpu耗时,默认只监控函数处理耗时,此选项可用于统计cpu占用信息
#mem_monitor : 是否监控内存占用信息
#ignored_functions: 忽略不监控的函数名数组,如下:
...
5.5 使用服务器端WEB UI
OK,到这里你已经成功完成部署,使用WEB UI的方式有如下两种:
1.直接访问服务器端首页url,基于web进行操作
2.在你的产品页面顶部,通过EXHPROF的链接地址来访问。如下:
6 FAQ
Q: 为什么我要申请空间?
A: 申请空间的目的是为了更好的管理服务器端数据存储。
如果不申请空间,而直接在客户端脚本中使用TAG名,服务器端会自动为你分配好空间,且不限制大小,但是客户端的数据存取带来的消耗会更大一些。
如果你申请空间,对于功能环境,你将可以获得2G的空间,已经足够满足日常测试的性能数据存储需求,并且客户端的数据存取带来的消耗相对小一些。如果数据超过2G,将会自动覆盖最老的数据。
Q: 我如何获得一个函数的全局调用堆栈?
A: Exhprof在底层使用了xhprof进行性能数据收集,xhprof只记录一级的调用上下文,因此只能回答关于一级一级函数调用的问题。而事实证明,在实践中这是最主要的利用情况。
如果你想了解全局的调用堆栈,可以通过子/父函数级视图进行逐级分析,来获得全局调用堆栈。当然Exhprof也可以为你实现全局调用堆栈的信息的查询(暂未实现)。
Q: 我如何直接查看某个函数的性能视图?
A:你可以在WEB页面右上角的搜索框里面输入你想查看的函数名,点击选择你想函数名即可
Q: 我在性能环境可以使用么?
A:当然可以。在性能和生产环境使用是本平台的特点,不过你需要注意在客户端脚本进行相关的配置,推荐使用$mode="press",具体的性能消耗请参考第4节