说明

将xhprof部署在线上环境,在特定情况下进行性能分析,方便快捷的排查线上性能问题。

通过参数指定及添加代码行触发进入性能分析,并将结果保存入MongoDB。

因为xhprof对性能的影响,只部署在一台机子上。

环境配置

PHP 5.5.25
xhprof-0.9.4

xhprof:git@github.com:phacility/xhprof.git

核心入口文件

/PATH/xhprof/config/inject.php


  1. <?php
  2. //根据条件是否进入性能分析
  3. if( !function_exists('xphrof_checkEnable') ){
  4. //返回值,ture-进入, false-不进入
  5. function xphrof_checkEnable($cmdName=''){
  6. //如果是脚本,直接进
  7. if( !empty($cmdName) ){
  8. return true;
  9. }
  10. //方法一:根据参数进
  11. $enable = !empty($_GET['showyourbug']) || !empty($_POST['showyourbug']);
  12. //方法二:根据百分比或随机
  13. //$enable = rand(0, 100) === 42;
  14. //方法三:使用唯一性数据(ip\host\op_user)
  15. return $enable;
  16. }
  17. }
  18. //获取标识请求的唯一性数据
  19. if( !function_exists('xphrof_getUniqSign') ){
  20. function xphrof_getUniqSign($cmdName=''){
  21. //请求的标识-ip
  22. $clientIp = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n');
  23. //请求的标识-路由
  24. $path = 'unknow';
  25. if( isset($_SERVER["REQUEST_URI"]) ){
  26. $purl = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
  27. $path = 'http-' . (!empty($purl) ? str_replace('/','-', trim($purl, ' /')) : 'unknow');
  28. }else{
  29. $path = 'cmd-' . ( !empty($cmdName) ? str_replace('\\','-', trim($cmdName, ' \\')): 'unknow');
  30. }
  31. //尝试从cookie中取用户名
  32. //执行分析的服务器
  33. $hostName = php_uname('n');
  34. return [
  35. 'ip' => $clientIp,
  36. 'path' => $path,
  37. 'hostname' => $hostName
  38. ];
  39. }
  40. }
  41. //主处理过程
  42. if( !function_exists('xphrof_mainProcess') ){
  43. function xphrof_mainProcess($cmdName=''){
  44. if ( extension_loaded('xhprof') ) {
  45. //xhprof功能统一开关,紧急情况下使用
  46. $xhprofMainSwitch = true; //true-开, false-关
  47. //判断是否进入分析
  48. $enable = xphrof_checkEnable($cmdName);
  49. if ( $xhprofMainSwitch && $enable ) {
  50. $pathData = xphrof_getUniqSign($cmdName);
  51. //开始性能分析
  52. // XHPROF_FLAGS_NO_BUILTINS - 使得跳过所有内置(内部)函数
  53. // XHPROF_FLAGS_CPU - 使输出的性能数据中添加 CPU 数据
  54. // XHPROF_FLAGS_MEMORY - 使输出的性能数据中添加内存数据
  55. xhprof_enable( XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU );
  56. //注册,脚本执行完或exit后执行
  57. register_shutdown_function(function() use ($pathData){
  58. //xhprof的数据
  59. $xhprofData = xhprof_disable();
  60. //相应给客户端并结束请求
  61. $returnClient = -1;
  62. if (function_exists('fastcgi_finish_request')) {
  63. $returnClient = fastcgi_finish_request();
  64. }
  65. //当前环境数据及post、get数据
  66. $envData = [
  67. 'env' => $_SERVER,
  68. 'get' => $_GET,
  69. 'post' => $_POST,
  70. 'return_client' => intval($returnClient)
  71. ];
  72. $XHPROF_ROOT = realpath(dirname(__FILE__) .'/..');
  73. include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
  74. include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs_mongo.php";
  75. include_once $XHPROF_ROOT . "/xhprof_lib/service/MongoBaseSvc.php";
  76. //加载配置文件
  77. $xhprofConfig = include_once $XHPROF_ROOT . '/config/config.php';
  78. $xhprofRuns = new XHProfRuns_Mongo($xhprofConfig);
  79. $xhprofRuns->save_run($xhprofData, $envData, $pathData);
  80. });
  81. }
  82. }
  83. }
  84. }
  85. //默认启动一次-http,指定服务器才可执行
  86. if( function_exists('php_uname') && in_array(php_uname('n'), [
  87. '10.10.10.10', //测试开发服务器
  88. '11.11.11.11' //线上执行服务器
  89. ], true) ){
  90. xphrof_mainProcess();
  91. }
  92. //comand进入分析
  93. if( !function_exists('xphrof_startProcess') ){
  94. function xphrof_startProcess($cmdName=''){
  95. xphrof_mainProcess($cmdName);
  96. }
  97. }

加载入口文件方案

1. 在项目启动的配置文件中加载


  1. //例如:bootstrap/autoload.php
  2. /*
  3. |--------------------------------------------------------------------------
  4. | add xhprof config
  5. |--------------------------------------------------------------------------
  6. |
  7. | inject xhprof config.
  8. |
  9. */
  10. $xhprofFile = __DIR__.'/../xhprof/config/inject.php';
  11. if (file_exists($xhprofFile)) {
  12. require_once $xhprofFile;
  13. }

2. 在项目nginx的配置中加载


  1. //在 nginx 的fastcgi配置处
  2. set $xhprofconf "auto_prepend_file=/PATH/xhprof/config/inject.php";
  3. fastcgi_param PHP_VALUE $xhprofconf;

触发进入

  1. 对HTTP请求访问时增加参数:showyourbug=1
  2. 对CLI脚本代码中增加:xphrof_startProcess(__CLASS__);

MongoDB保存结构

解析保存xhprof_disable()返回的数据、请求的环境变量及数据。可设置过期索引保存指定时长日志。


  1. {
  2. "ip" : "10.10.10.10", //访问客户端ip
  3. "path" : "http-", //资源标识,http-接口请求,cmd-artisan脚本执行
  4. "hostname" : "machine_host_name", //执行机器名称
  5. "run_id" : "5afe795c96a83", //唯一run_id
  6. "main" : { //整体数据
  7. "ct" : NumberLong(1),
  8. "wt" : NumberLong(36),
  9. "cpu" : NumberLong(0),
  10. "mu" : NumberLong(1856),
  11. "pmu" : NumberLong(672)
  12. },
  13. "xhprof_raw_data" : "a:2:{s:23:\"main()==>xhprof_disable\";a:5:{s:2:\"ct\";i:1;s:2:\"wt\";i:8;s:3:\"cpu\";i:0;s:2:\"mu\";i:840;s:3:\"pmu\";i:96;}s:6:\"main()\";a:5:{s:2:\"ct\";i:1;s:2:\"wt\";i:36;s:3:\"cpu\";i:0;s:2:\"mu\";i:1856;s:3:\"pmu\";i:672;}}", //原始数据体
  14. "env_data" : { //相关环境日志
  15. "env" : { //$_SERVER信息
  16. "USER" : "nobody",
  17. "HOME" : "/",
  18. "FCGI_ROLE" : "RESPONDER",
  19. "SCRIPT_FILENAME" : "/PATH/public/index.php",
  20. ......
  21. "REQUEST_TIME" : NumberLong(1526626652)
  22. },
  23. "get" : { //$_GET信息
  24. "showyourbug" : "1"
  25. },
  26. "post" : [], //$_POST信息
  27. "return_client" : NumberLong(-1) //fastcgi_finish_request相应客户端结果
  28. },
  29. "index_time" : ISODate("2018-05-18T06:57:32.000Z"), //过期索引,保留2天
  30. "create_time" : "2018-05-18 14:57:32" //创建时间
  31. }

对线上性能的影响分析

测试接口


  1. public function getHello(){
  2. $ret = [
  3. 'errno' => 0,
  4. 'errmsg' => 'success'
  5. ];
  6. return json_encode($ret);
  7. }

使用ab请求


  1. ab -n 1000 -c 100 -X 10.10.10.10:80 http://hostname/hello
  2. ab -n 1000 -c 100 -X 10.10.10.10:80 http://hostname/hello?showyourbug=1

测试结果
批量请求对服务器影响:
| 测试类别 | Requests per second (#/sec) | 平均 | Time per request (ms) | 平均 |
| 仅测试接口 | 49.23,50.02,49.41 | 49.55 | 20.312,19.992,20.239 | 20.181 |
| 加载配置(未进入) | 46.74,45.48,45.21 | 45.81 (-8.76%) | 21.397,21.987,22.118 | 21.834 (-8.19%) |
| 加载配置(进入) | 10.72,10.48,11.46 | 10.88 (-78%) | 93.281,95.452,87.259 | 91.99 (-355.82%) |

对单个请求影响:
| 测试类别 | Time per request (ms) | 平均 |
| 仅测试接口 | 66.972,87.029,72.605 | 75.54 |
| 加载配置(未进入) | 79.183,80.728,83.101 | 81.004 (-7.23%) |
| 加载配置(进入) | 275.186,287.293,291.312 | 284.597 (-271.45%) |

结论

xhprof会影响线上性能,所以只部署到一台线上机进行监控。

原文地址:https://segmentfault.com/a/1190000015591262

xphrof性能分析线上部署实践的更多相关文章

  1. ASP.NET Core在CentOS上的最小化部署实践

    引言        本文从Linux小白的视角, 在CentOS 7.x服务器上搭建一个Nginx-Powered AspNet Core Web准生产应用. 在开始之前,我们还是重温一下部署原理,正 ...

  2. 在阿里云ECS CentOS7上部署基于MongoDB+Node.js的博客

    前言:这是一篇教你如何在阿里云的ECS CentOS 7服务器上搭建一个个人博客的教程,教程比较基础,笔者尽可能比较详细的把每一步都罗列下来,包括所需软件的下载安装和域名的绑定,笔者在此之前对Linu ...

  3. VNF网络性能提升解决方案及实践

    VNF网络性能提升解决方案及实践 2016年7月 作者:    王智民 贡献者:     创建时间:    2016-7-20 稳定程度:    初稿 修改历史 版本 日期 修订人 说明 1.0 20 ...

  4. 腾讯云-ASP.NET Core+Mysql+Jexus+CDN上云实践

    腾讯云-ASP.NET Core+Mysql+Jexus+CDN上云实践.md 开通腾讯云服务器和Mysql 知识点: ASP.NET Core和 Entity Framework Core的使用 L ...

  5. zz开源 MNN:淘宝在移动 AI 上的实践

    开源 MNN:淘宝在移动 AI 上的实践   陈以鎏(离青) 阅读数:40612019 年 6 月 28 日   随着深度学习的快速发展和端侧设备算力的不断提升,原本在云端执行的推理预测工作正在部分迁 ...

  6. 滴滴推理引擎IFX:千万规模设备下AI部署实践

    桔妹导读:「滴滴技术」将于本月开始,联合各技术团队为大家带来精彩分享.你想了解的技术干货,深度专访,团队及招聘将于每周三与你准时见面.本月为「滴滴云平台事业群分享月」,在今天的内容中,云平台事业群-机 ...

  7. 在 CentOS7 上部署 zookeeper 服务

    在 CentOS7 上部署 zookeeper 服务 1 用 SecureCRT 或 XShell 等 Linux 客户端工具连接至 CentOS7 服务器: 2 进入到 /usr/local/too ...

  8. [转]基于AWS的自动化部署实践

    作者 徐桂林 发布于 2014年1月22日 -------------------------------------------------------------------- 1. 背景 在过去 ...

  9. 虚拟机评估——如何确定一个CPU核上部署的虚拟机数量?

    最近研究虚拟化技术,不可避免遇到一个问题:如何评估物理主机上虚拟主机的容量?下面这篇文章的思路有一定的启发性,转发一下. 如何确定一个CPU核上部署的虚拟机数量? 摘要:本文说明一个CPU核上部署虚拟 ...

随机推荐

  1. Ruby  String类

    String类 更新: 2017/06/10 更新: 2017/06/23 puts()要空格可以直接不加参数 更新: 2017/08/17 增加rails引入的titleize 更新: 2017/1 ...

  2. poj 3130 How I Mathematician Wonder What You Are! 【半平面交】

    求多边形的核,直接把所有边求半平面交判断有无即可 #include<iostream> #include<cstdio> #include<algorithm> # ...

  3. Ocelot(十二)- 请求聚合

    Ocelot允许您指定聚合多个普通ReRoutes的Aggregate ReRoutes(聚合路由),并将其响应映射到一个对象中.一般用于当您有一个客户端向服务器发出多个请求,而这些请求可以合并成一个 ...

  4. mysql查询流程

    首先是连接器 连接器负责跟客户端来链接 链接成功后 mysql会先去查询缓存,之前是不是有查询的这条语句,之前执行过的话 就会以key-value的形式缓存到内存中,如果没有就会继续执行后面的,执行完 ...

  5. 【SpringCloud构建微服务系列】使用Spring Cloud Config统一管理服务配置

    一.为什么要统一管理微服务配置 对于传统的单体应用而言,常使用配置文件来管理所有配置,比如SpringBoot的application.yml文件,但是在微服务架构中全部手动修改的话很麻烦而且不易维护 ...

  6. InputFilter在过滤空格时重复输入的问题

    正确做法:editText.setFilters(new InputFilter[] { new InputFilter() { @Override public CharSequence filte ...

  7. _bzoj1208 [HNOI2004]宠物收养所【Splay】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1208 以后在空间限制允许的情况下我绝对不纠结内存占用问题啦!就因为不舍得用long long ...

  8. log4js日志配置问题

    http://blog.csdn.net/cdnight/article/details/50857268 在做项目中,我们的node日志采用的是log4js框架,使用文件方式存储,但在后面的需求中增 ...

  9. iOS开发之邮件发送代码

    邮件发送功能是由MessageUI Framework提供的,这个框架是iPhone sdk中最简单的框.由一个类.一个视图控制器,一个protocol组成. 一.创建视图控制器: MFMailCom ...

  10. sdut1282Find the Path (floyd变形)

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=1282 感觉这题就比较有意思了 ,虽说是看了别人 ...