使用xhprof進行線上PHP性能追蹤及分析

jopen 9年前發布 | 20K 次閱讀 PHP PHP開發

之前一直使用基于Xdebug進行PHP的性能分析,對于本地開發環境來說是夠用了,但如果是線上環境的話,xdebug消耗較大,配置也不夠靈活,因此線上環境建議使用xhprof進行PHP性能追蹤及分析

xhprof的安裝與簡易用法

xhprof是非死book開源的輕量級PHP性能分析工具,Linux環境下可以通過pecl直接安裝,比如在Ubuntu下僅需3行指令

pecl install xhprof-beta
echo "extension=xhprof.so" > /etc/php5/fpm/conf.d/xhprof.ini
service php5-fpm restart 

之后可以通過phpinfo()檢查擴展是否已經加載。

具體如何使用呢,xhprof項目中已經提供了示例以及簡易的UI,下載xhprof項目到web服務器,假設可以通過http://localhost/xhprof/訪問,那么訪問http://localhost/xhprof/examples/sample.php可以看到一些輸出,并且提示通過訪問http://<xhprof-ui-address>/index.php?run=XXX&source=xhprof_foo查看結果。接下來訪問http://localhost/xhprof/xhprof_html/就可以看到已經保存的結果,列出了所有函數的調用以及所消耗的時間。

分析一下示例代碼sample.php,關鍵部分只有2行:

//開啟xhprof并開始記錄 xhprof_enable(); //運行一些函數 foo(); //停止記錄并取到結果 $xhprof_data = xhprof_disable();

$xhprof_data中記錄了程序單步運行過程中所有的函數調用時間及CPU內存消耗等,具體記錄哪些指標可以通過xhprof_enable的入口參數控制,之后的處理已經與xhprof擴展無關,大致是編寫了一個存儲類XHProfRuns_Default,將$xhprof_data序列化并保存到某個目錄,可以通過XHProfRuns_Default(__DIR__)將結果輸出到當前目錄,如果不指定則會讀取php.ini配置文件中的xhprof.output_dir,仍然沒有指定則會輸出到/tmp。

xhprof_html/index.php將記錄的結果整理并可視化,默認的UI里列出了:

  • funciton name : 函數名
  • calls: 調用次數
  • Incl. Wall Time (microsec): 函數運行時間(包括子函數)
  • IWall%:函數運行時間(包括子函數)占比
  • Excl. Wall Time(microsec):函數運行時間(不包括子函數)
  • EWall%:函數運行時間(不包括子函數)
  • </ul>

    每一項應該不難理解,以項目自帶的sample.php為例,示例中編寫了一個main()函數,main()函數中調用foo()、bar()等一些子函數進行了一點字符處理。整個程序運行過程中,main()函數只運行了一次,并且由于main()函數中包括了所有的邏輯,所以main()函數的IWall%占比為100%,但是由于main()函數的功能都是由子函數實現的,因此main()函數的EWall%只有0.3%,而foo()函數完成了主要的工作,EWall%有98.1%。因此在分析更大型的程序時,往往需要根據這幾項指標分別排序,從不同的角度審視性能消耗。

    在xhprof_html/index.php中還可以看到[View Full Callgraph]鏈接,點擊后可以繪制出一張可視化的性能分析圖,如果點擊后報錯的話,可能是缺少依賴graphviz,ubuntu可以通過apt安裝

    apt-get install graphviz

    更好的注入方式

    了解了上面這些,其實就已經可以將xhprof整合到任何我們已有的項目中去了。目前大部分MVC框架都有唯一的入口文件,只需要在入口文件的開始處注入xhprof的邏輯

    //開啟xhprof 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();
        } //保存xhprof數據 ...
    });

    但是這樣免不了要修改項目的源代碼,其實php本身就提供了更好的注入方式,比如將上述邏輯保存為/opt/inject.php,然后修改php fpm配置文件

    vi /etc/php5/fpm/php.ini

    修改auto_prepend_file配置

    auto_prepend_file = /opt/inject.php 

    這樣所有的php-fpm請求的php文件前都會自動注入/opt/inject.php文件

    如果使用Nginx的話,還可以通過Nginx的配置文件設置,這樣侵入性更小,并且可以實現基于站點的注入。

    fastcgi_param PHP_VALUE "auto_prepend_file=/opt/inject.php";

    更好的分析工具:xhprof.io還是xhpgui

    注入代碼后我們還需要實現保存xhprof數據以及展示數據的UI,聽起來似乎又是一大堆工作,有現成的輪子可以用嗎?

    經過搜索和比較,貌似比較好的選擇有xhprof.io以及xhpgui

    兩個項目做得事情差不多,都提供了xhprof數據保存功能以及一套索引展示數據的UI,下面是一些比較

    xhprof.io

    • ? 年久失修
    • ? 保存xhprof數據到MySQL
    • ? 支持域名、URI等多個維度的數據索引
    • ? 函數調用記錄完整,內核級別函數都能顯示
    • ? 無法針對個別URI開啟
    • ? 注入被分割成兩個文件,如果程序被強制中斷時xhprof數據將無法收集
    • </ul>

      xhgui

      • ? 保存xhprof數據到MongoDB
      • ? 不支持域名索引
      • ? 函數調用記錄不完整,部分內核級別函數(如擴展內)無法顯示
      • ? 有配置文件可以控制開啟條件
      • ? 注入只有一個文件
      • ? 狂拽酷炫的基于D3.js的調用關系動態圖
      • </ul>

        可以看到其實兩個項目都不夠完善,相對而言xhgui不支持域名索引對于線上調試來說是無法忍受的,因此我最后的選擇是使用xhprof.io,但是自己進行了微量的調整,修改后的xhprof.io修正版支持:

        • ? 增加開啟開關配置,可以針對個別URI開啟
        • ? 注入文件合并為一個
        • </ul>

          xhprof.io修正版安裝與使用

          安裝及配置方法如下,假設web服務器根目錄為/opt/htdocs

          cd /opt/htdocs
          git clone https://github.com/EvaEngine/xhprof.io.git cd xhprof.io/
          composer install
          cp xhprof/includes/config.inc.sample.php xhprof/includes/config.inc.php 
          vi xhprof/includes/config.inc.php

          在MySQL中建立xhprof.io數據庫,假設數據庫名為xhprof,然后導入xhprof/setup/database.sql

          配置文件config.inc.php中需要調整

          • 'url_base' => 'http://localhost/xhprof.io/',這是xhprof.io界面所在路徑
          • 'pdo' => new PDO('mysql:dbname=xhprof;host=localhost;charset=utf8', 'root', 'password'),根據MySQL實際情況調整配置
          • enable這是一個匿名函數,當匿名函數返回true時啟用xhprof數據收集
          • </ul>

            通過配置enable項,就可以實現線上調試的需求,比如

            始終開啟xhprof

            'enable' => function() { return true;
            }

            1/100概率隨機開啟xhprof

            'enable' => function() { return rand(0, 100) === 1;
            }

            網頁攜帶參數debug=1時開啟xhprof

            'enable' => function() { return !empty($_GET['debug']);
            }

            網頁URL為特定路徑時開啟

            'enable' => function() { return strpos($_SERVER['REQUEST_URI'], '/testurl') === 0;
            }

            最后按上文所述,在要配置的項目中包含xhprof.io/inc/inject.php即可。

            線上環境操作時務必要膽大心細,如果沒有結果尤其注意需要檢查xhprof擴展是否安裝

            附錄:xhpgui的安裝方法

            apt-get install mongodb php5-mongo php5-mcrypt
            cp /etc/php5/mods-available/mcrypt.ini /etc/php5/fpm/conf.d/
            cp /etc/php5/mods-available/mcrypt.ini /etc/php5/cli/conf.d/
            cd /opt/htdocs
            git clone https://github.com/perftools/xhgui.git cd xhgui
            composer install
            cp config/config.default.php config/config.php
            chown www-data.www-data -R cache

            編輯Nginx配置文件加入

            fastcgi_param PHP_VALUE "auto_prepend_file=/opt/htdocs/xhgui/external/header.php";

            收集數據過多時可以清空mongodb

            mongo use xhprof;
            db.dropDatabase();
            來自:http://avnpc.com/pages/profiler-php-performance-online-by-xhprof

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!