將xhprof部署在線上環境,在特定狀況下進行性能分析,方便快捷的排查線上性能問題。php
經過參數指定及添加代碼行觸發進入性能分析,並將結果保存入MongoDB。nginx
由於xhprof對性能的影響,只部署在一臺機子上。git
PHP 5.5.25
xhprof-0.9.4github
xhprof:git@github.com:phacility/xhprof.gitjson
/PATH/xhprof/config/inject.phpbootstrap
<?php //根據條件是否進入性能分析 if( !function_exists('xphrof_checkEnable') ){ //返回值,ture-進入, false-不進入 function xphrof_checkEnable($cmdName=''){ //若是是腳本,直接進 if( !empty($cmdName) ){ return true; } //方法一:根據參數進 $enable = !empty($_GET['showyourbug']) || !empty($_POST['showyourbug']); //方法二:根據百分比或隨機 //$enable = rand(0, 100) === 42; //方法三:使用惟一性數據(ip\host\op_user) return $enable; } } //獲取標識請求的惟一性數據 if( !function_exists('xphrof_getUniqSign') ){ function xphrof_getUniqSign($cmdName=''){ //請求的標識-ip $clientIp = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n'); //請求的標識-路由 $path = 'unknow'; if( isset($_SERVER["REQUEST_URI"]) ){ $purl = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); $path = 'http-' . (!empty($purl) ? str_replace('/','-', trim($purl, ' /')) : 'unknow'); }else{ $path = 'cmd-' . ( !empty($cmdName) ? str_replace('\\','-', trim($cmdName, ' \\')): 'unknow'); } //嘗試從cookie中取用戶名 //執行分析的服務器 $hostName = php_uname('n'); return [ 'ip' => $clientIp, 'path' => $path, 'hostname' => $hostName ]; } } //主處理過程 if( !function_exists('xphrof_mainProcess') ){ function xphrof_mainProcess($cmdName=''){ if ( extension_loaded('xhprof') ) { //xhprof功能統一開關,緊急狀況下使用 $xhprofMainSwitch = true; //true-開, false-關 //判斷是否進入分析 $enable = xphrof_checkEnable($cmdName); if ( $xhprofMainSwitch && $enable ) { $pathData = xphrof_getUniqSign($cmdName); //開始性能分析 // XHPROF_FLAGS_NO_BUILTINS - 使得跳過全部內置(內部)函數 // XHPROF_FLAGS_CPU - 使輸出的性能數據中添加 CPU 數據 // XHPROF_FLAGS_MEMORY - 使輸出的性能數據中添加內存數據 xhprof_enable( XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU ); //註冊,腳本執行完或exit後執行 register_shutdown_function(function() use ($pathData){ //xhprof的數據 $xhprofData = xhprof_disable(); //相應給客戶端並結束請求 $returnClient = -1; if (function_exists('fastcgi_finish_request')) { $returnClient = fastcgi_finish_request(); } //當前環境數據及post、get數據 $envData = [ 'env' => $_SERVER, 'get' => $_GET, 'post' => $_POST, 'return_client' => intval($returnClient) ]; $XHPROF_ROOT = realpath(dirname(__FILE__) .'/..'); include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php"; include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs_mongo.php"; include_once $XHPROF_ROOT . "/xhprof_lib/service/MongoBaseSvc.php"; //加載配置文件 $xhprofConfig = include_once $XHPROF_ROOT . '/config/config.php'; $xhprofRuns = new XHProfRuns_Mongo($xhprofConfig); $xhprofRuns->save_run($xhprofData, $envData, $pathData); }); } } } } //默認啓動一次-http,指定服務器纔可執行 if( function_exists('php_uname') && in_array(php_uname('n'), [ '10.10.10.10', //測試開發服務器 '11.11.11.11' //線上執行服務器 ], true) ){ xphrof_mainProcess(); } //comand進入分析 if( !function_exists('xphrof_startProcess') ){ function xphrof_startProcess($cmdName=''){ xphrof_mainProcess($cmdName); } }
1. 在項目啓動的配置文件中加載服務器
//例如:bootstrap/autoload.php /* |-------------------------------------------------------------------------- | add xhprof config |-------------------------------------------------------------------------- | | inject xhprof config. | */ $xhprofFile = __DIR__.'/../xhprof/config/inject.php'; if (file_exists($xhprofFile)) { require_once $xhprofFile; }
2. 在項目nginx的配置中加載cookie
//在 nginx 的fastcgi配置處 set $xhprofconf "auto_prepend_file=/PATH/xhprof/config/inject.php"; fastcgi_param PHP_VALUE $xhprofconf;
解析保存xhprof_disable()返回的數據、請求的環境變量及數據。可設置過時索引保存指定時長日誌。函數
{ "ip" : "10.10.10.10", //訪問客戶端ip "path" : "http-", //資源標識,http-接口請求,cmd-artisan腳本執行 "hostname" : "machine_host_name", //執行機器名稱 "run_id" : "5afe795c96a83", //惟一run_id "main" : { //總體數據 "ct" : NumberLong(1), "wt" : NumberLong(36), "cpu" : NumberLong(0), "mu" : NumberLong(1856), "pmu" : NumberLong(672) }, "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;}}", //原始數據體 "env_data" : { //相關環境日誌 "env" : { //$_SERVER信息 "USER" : "nobody", "HOME" : "/", "FCGI_ROLE" : "RESPONDER", "SCRIPT_FILENAME" : "/PATH/public/index.php", ...... "REQUEST_TIME" : NumberLong(1526626652) }, "get" : { //$_GET信息 "showyourbug" : "1" }, "post" : [], //$_POST信息 "return_client" : NumberLong(-1) //fastcgi_finish_request相應客戶端結果 }, "index_time" : ISODate("2018-05-18T06:57:32.000Z"), //過時索引,保留2天 "create_time" : "2018-05-18 14:57:32" //建立時間 }
測試接口post
public function getHello(){ $ret = [ 'errno' => 0, 'errmsg' => 'success' ]; return json_encode($ret); }
使用ab請求
ab -n 1000 -c 100 -X 10.10.10.10:80 http://hostname/hello 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會影響線上性能,因此只部署到一臺線上機進行監控。