讓PHP程序員工作更高效的四大神器
做程序猿「媛」是一個(gè)苦逼的活,大周六地早起在技術(shù)群里招呼,看到?jīng)]有啥人響應(yīng),說(shuō)了一句,「估計(jì)都沒(méi)有醒」,然后一位哥們拋過(guò)來(lái),「在加班」 !
做 Web 開(kāi)發(fā)更是一個(gè)苦逼的活,不像是做 iOS,搞定客戶端,基本上就萬(wàn)事大吉了。做 Web 開(kāi)發(fā)不僅僅是要做后端,前端也需要了解和熟悉!
做前后端通吃的 DevOps 全棧工程師絕對(duì)是最苦逼的活,不但需要做開(kāi)發(fā),而且還要了解運(yùn)維、優(yōu)化,不會(huì)運(yùn)維的工程師絕對(duì)不是一個(gè)好架構(gòu)師!
但所幸的事,一個(gè)優(yōu)秀的工程師盡管很忙,盡管要熟悉前后端、系統(tǒng)、運(yùn)營(yíng)、優(yōu)化,但是在他的工具箱里,放著一大堆工具,讓這種生活變得不那么苦逼。
這里就介紹四個(gè)讓我們 DevOps 生活變得美好的神器。分別是 Xdebug、XHProf 、 OneAPM 和 SocketLog。
Xdebug
作為開(kāi)發(fā)人員,睡得最踏實(shí)的事是對(duì)自己寫的代碼了如指掌,無(wú)論是從功能層面,還是性能層面。而做 Web PHP 開(kāi)發(fā),比較棘手的一件事情就是代碼的調(diào)試。作為腳本語(yǔ)言,在遠(yuǎn)程服務(wù)器端運(yùn)行,客戶端生成的全是 HTML 代碼,一般認(rèn)為我們無(wú)法準(zhǔn)確地調(diào)試運(yùn)行的情況,更不要說(shuō)單步調(diào)試、變量監(jiān)控等事情了。其實(shí)這是有誤解的,有一個(gè) PHP 擴(kuò)展 Xdebug 能讓方便地讓我們調(diào)試遠(yuǎn)程服務(wù)器上運(yùn)行的代碼。
方法很簡(jiǎn)單,從 Xdebug 下載***版的源代碼。 wget 解壓:
tar –zxvf xdebug-2.3.3.tgz
cd xdebug-2.3.3 phpize
./configure –with-php-config=/usr/bin/php-config
make
make install
再增加相應(yīng)的配置到 php.ini
,需要注意有兩點(diǎn):
1. xdebug 是 zend_extension
2. 端口默認(rèn)是 9000,和 php-fpm 的缺省端口沖突,所以這里換用 9100
[xdebug]
zend_extension=/usr/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so
xdebug.remote_enable=on
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9100
這樣就裝好了,就是如此簡(jiǎn)單,下面我們可以開(kāi)始使用了。以 ThinkPHP 應(yīng)用開(kāi)發(fā)做例子吧。ThinkPHP 典型的單入口應(yīng)用,調(diào)用層次相對(duì)復(fù)雜。所以想要了解調(diào)用堆棧還是比較麻煩的。要想得到某一行的調(diào)用堆棧,可以使用 PHP 自帶的 debug_backtrace
函數(shù)可以獲得,但是不怎么形象,返回來(lái)一個(gè)數(shù)組而已。而 Xdebug 就能讓這一切可視化起來(lái)。
配合 Xdebug 使用的是 Netbeans 自帶的調(diào)試工具。首先通過(guò)***項(xiàng)修改了一下 PHP 調(diào)試的端口,從9000改成9100,其他不用動(dòng)。注意 在***行停止 是選上的,這將在 PHP 程序調(diào)試時(shí),運(yùn)行到***行 PHP 代碼時(shí)停止,在 ThinkPHP 中,即入口文件 index.php 的***行停止。
在本例中,筆者做了一個(gè)租車管理系統(tǒng)的示例,項(xiàng)目名為 zuches 。將代碼部署在 http://localhost/zuches
能訪問(wèn)的地方,索引文件是 index.php。
由于 index.php 是入口文件,所以在 index.php 上點(diǎn)擊右鍵,選擇調(diào)試。
然后 Netbeans 自動(dòng)打開(kāi)了如下地址,進(jìn)入調(diào)試狀態(tài) : http://localhost/zuches/index.php?XDEBUG_SESSION_START=netbeans-xdebug
同時(shí)運(yùn)行位置指示停留到了 index.php 的***行。如下:
點(diǎn)擊繼續(xù)運(yùn)行,由于在 IndexController.class.php
的 index
方法中加上了斷點(diǎn),所以位置指示又停留在了相應(yīng)的斷點(diǎn)處。
這個(gè)時(shí)候,我們可以查看中斷時(shí)候的調(diào)用堆棧和變量了。通過(guò)堆棧可以方便地定位到各定位的類和相應(yīng)方法。
各種變量,無(wú)論是局部變量和實(shí)例屬性,無(wú)論是 cookie,還是提交數(shù)據(jù),都能在變量表中看到,一目了然。
總之,Xdebug 讓我們即使做的是服務(wù)器端頁(yè)面和 API 開(kāi)發(fā),也可以像桌面應(yīng)用開(kāi)發(fā)一樣,調(diào)試每一行代碼了。
Xdebug 除了使用來(lái)進(jìn)行單步調(diào)試之外,還能收集請(qǐng)求中的執(zhí)行日志,記錄每一個(gè)函數(shù)的執(zhí)行過(guò)程。這些日志可以用 wincachegrind
等工具進(jìn)行分析,看到函數(shù)的調(diào)用棧和所花的時(shí)間。這里不再贅述,我們也不是很推薦,因?yàn)?XHProf
在這塊要輕量級(jí)和強(qiáng)大的多,不用如此費(fèi)勁地下載日志,分析日志。
#p#
XHProf
如前文所述,對(duì)于 PHP 中函數(shù)調(diào)用棧和性能分析,XHProf 將 Xdebug 開(kāi)的先河繼承并發(fā)揚(yáng)光大。XHProf 也是 PHP 擴(kuò)展,不過(guò)不建議從 http://pecl.php.net/package/xhprof 上下載,版本已有近2年沒(méi)有更新了,***從 https://github.com/phacility/xhprof 上下載。下載編譯配置和使用過(guò)程都很簡(jiǎn)單。
配置只需要加上如下兩行:
``` [xhprof] extension=/usr/lib/php/extensions/no-debug-non-zts-20121212/xhprof.so
然后將要相應(yīng)的 XHProf 代碼配置到需要監(jiān)控的頁(yè)面中,即可以獲得整個(gè)頁(yè)面的執(zhí)行中,各函數(shù)的調(diào)用報(bào)表。XHProf 提供了示例,配置成功運(yùn)行如下:
如何看到上面圖中的效果呢?將 examples
、 xhprof_html
、 xhprof_lib
三個(gè)目錄放到瀏覽器能訪問(wèn)到的地方,比如 localhost
的主目錄內(nèi)。修改 examples/sample.php
中的 <xhprof-ui-address>
換成 如: localhost/xhprof_html/
。即可。
然后訪問(wèn) http://localhost/examples/sample.php
即可以得到輸出結(jié)果如下:
從 examples/sample.php
中可以看到,對(duì)于頁(yè)面的監(jiān)測(cè)分析,在頁(yè)面頂部使用 xhprof_enable
開(kāi)始,而性能的分析的結(jié)束,則是在頁(yè)面底部使用 xhprof_disable
結(jié)束 。這樣每次監(jiān)控,都需要增加一段代碼,所以為了規(guī)范起見(jiàn)。對(duì) XHProf 相關(guān)的操作進(jìn)行了封裝。繼續(xù)采用上例 ThinkPHP 版租車系統(tǒng)的例子,看看如何集成 XHProf 分析。
首先將對(duì) XHProf 的操作封裝成了一個(gè)類。
<?php class XHProf { private static $strNameSpace = ""; public static function init($strNameSpace = "myhome") { if (!function_exists("xhprof_enable")) { return; } self::$strNameSpace = strval($strNameSpace); $param = XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY; $path = getcwd(); require_once $path.'/../xhprof_lib/utils/xhprof_lib.php'; require_once $path.'/../xhprof_lib/utils/xhprof_runs.php'; xhprof_enable($param); register_shutdown_function("XHProf::genResult"); } public static function genResult() { $profiler_namespace = self::$strNameSpace; $xhprof_data = xhprof_disable(); $xhprof_runs = new XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, $profiler_namespace); $profiler_url = sprintf('http://' . $_SERVER['HTTP_HOST'] . '/xhprof_html/index.php? run=%s&source=%s', $run_id, $profiler_namespace); echo '<p style="position:absolute; left:0; top:0; background:orange; padding:8px;">' . '<a href="' . $profiler_url . '" target="_blank">Profiler output</a></p>';
}
}
在這個(gè)封裝的類中,首先檢測(cè)了 xhprof_enable
函數(shù)是否存在,這可以用于判斷是否成功安裝配置了 xhprof
擴(kuò)展。其次設(shè)置了參數(shù),特別值得一提的是使用函數(shù) register_shutdown_function
來(lái)注冊(cè)一個(gè)操作,這個(gè)操作在頁(yè)面結(jié)束之前,會(huì)自動(dòng)運(yùn)行。
這樣,在分析頁(yè)面性能之時(shí),只需要在 ThinkPHP 應(yīng)用的 index.php
上加上兩行,即可以了。
比如:
require_once "xhprof.php"; XHProf::init("zuches");
運(yùn)行后,得到如下效果:
并且每一個(gè)頁(yè)面,都有這樣的輸出。點(diǎn)擊「Profiler output」即得到了報(bào)表。
在本例中,可以看到***的集成方法,運(yùn)行時(shí)間超過(guò)了2 S,是值得關(guān)注并優(yōu)化了。從報(bào)表中,可以首先看到各個(gè)方法或者函數(shù)的調(diào)用次數(shù),運(yùn)行時(shí)間,以及可以層層點(diǎn)進(jìn)去看到父子層級(jí)的調(diào)用關(guān)系 。
需要注意的是,在線上,如上使用 XHProf 要慎重,即使打開(kāi),也要有限制條件地打開(kāi),比如當(dāng)前用戶是某些調(diào)試開(kāi)發(fā)者用戶時(shí)才打開(kāi)。否則,普通用戶看到這樣的輸出,則不明所以,給用戶帶來(lái)困惑,當(dāng) 然,我們也可以不輸出,而將數(shù)據(jù)直接存儲(chǔ),在后臺(tái)系統(tǒng)中查看,這樣用戶就感受不到了。有一個(gè)工具,可以完全消除這些糾結(jié)。那就是 OneAPM ,在第四部分我們?cè)俳榻B。
#p#
SocketLog
作為程序員,除了新功能開(kāi)發(fā)之外,最常見(jiàn)的一個(gè)工作就是查錯(cuò),尤其是遠(yuǎn)程用戶的查錯(cuò),還是一個(gè)很痛苦的過(guò)程。當(dāng)前又加上了微信開(kāi)發(fā),API 開(kāi)發(fā)等操作。對(duì)于微信內(nèi)、API 由遠(yuǎn)程用戶所調(diào)用的時(shí)候,情況多變,查錯(cuò)也更加地麻煩。這個(gè)時(shí)候,我們的第三個(gè)神器登場(chǎng)了。那就是 SocketLog。
SocketLog 是國(guó)內(nèi)知名 PHP 開(kāi)發(fā)者羅飛的作品,羅飛是 ThinkPHP 的核心開(kāi)發(fā)者,也是優(yōu)才學(xué)院全棧工程師主力講師?,F(xiàn)任三生社群 CTO。SocketLog 的 github 地址為: https://github.com/luofei614/SocketLog
,在項(xiàng)目的主頁(yè)上,詳細(xì)地介紹了用法和所用的技術(shù)。這里簡(jiǎn)單地匯總講解一下。
SocketLog 的使用,主要要分成三個(gè)步驟,***步是安裝 Chrome 插件??梢詮?github 下載的安裝包中去安裝,或者可以從 Chrome 應(yīng)用商店下載。
第二步是需要啟動(dòng) Socket 服務(wù),Socket 服務(wù)是 WebSocket 協(xié)議的,早期版本是 PHP 編寫的服務(wù)器,新的版本已經(jīng)使用 Node.js 來(lái)實(shí)現(xiàn)了。啟動(dòng)方法很簡(jiǎn)單,進(jìn)入解壓后的目錄。
執(zhí)行 node server/index.js
即可。
安裝好插件之后,就在 Chrome 上看到如下圖標(biāo)?;疑硎緵](méi)有連接上。
同時(shí)啟動(dòng)了服務(wù)器,做好設(shè)置,就會(huì)看到圖標(biāo)變成藍(lán)色了。
需要注意的是,盡管我們這里監(jiān)聽(tīng)地址配置成了本地地址,其實(shí)也可以配置遠(yuǎn)程地址。不過(guò)遠(yuǎn)程地址的話記得打開(kāi)服務(wù)器上的防火墻,因?yàn)橐话?229端口在防火墻中是關(guān)閉的。
SocketLog 的原理,是在服務(wù)器端,往 WebSocket 服務(wù)器上寫數(shù)據(jù),作為客戶端的 Chrome 插件,即能收到數(shù)據(jù)。所以不管是遠(yuǎn)程 API 調(diào)用,還是網(wǎng)頁(yè)訪問(wèn),只要在程序中往這個(gè) WebSocket 服務(wù)器寫了數(shù)據(jù),只要監(jiān)聽(tīng)了這個(gè) Websocket 服務(wù)的客戶端都能收到相應(yīng)的調(diào)試日志。
第三步是埋代碼。使用方法也很簡(jiǎn)單。比如我們?cè)谏厦娴?ThinkPHP 的 index.php 加入兩行代碼。會(huì)看到如下輸出 。
然后我們?cè)谄渌K端上也訪問(wèn)一下這臺(tái)機(jī)器的這個(gè)頁(yè)面地址,看看是否能得到輸出呢?開(kāi)始沒(méi)有任何輸出效果。因?yàn)槿笔∏闆r下是不記錄普通用戶所調(diào)用的 slog 的。
在 slog 之上的語(yǔ)句加上這一行,就有了。
slog(array('force_client_id'=>'test'),'set_config');
Test 這個(gè)插件的用戶,收到了所有的 slog 消息。如下圖所示:
并且這種輸出 ,無(wú)論是別的用戶觸發(fā),而還后臺(tái)服務(wù)程序,均可以輸出 。所以非常地方便,開(kāi)發(fā)人員在自己的機(jī)器上就收集到了想要收集的用戶所觸發(fā)的調(diào)試信息。
然后為了體現(xiàn)對(duì) SQL 語(yǔ)句的監(jiān)聽(tīng)。我們?cè)?ThinkPHP/Library/Think/Db/Driver.class.php
的第1139行加上 slog($str)
,然后再訪問(wèn)頁(yè)面,就得到了如下輸出 ,可見(jiàn)實(shí)現(xiàn)了對(duì) SQL 日志的監(jiān)控。
SocketLog 的功能看起來(lái)雖然簡(jiǎn)單,但是卻非常有用、好用,是***的開(kāi)發(fā)神器。有關(guān) SocketLog 的更多介紹和使用說(shuō)明,建議現(xiàn)在就立刻下載,并且進(jìn)入 github 主頁(yè)好好地研究吧!
#p#
OneAPM
從上面的使用來(lái)看,SocketLog 和 XHProf 都有兩個(gè)不足之處,一是需要埋代碼,二是只是基于單獨(dú)一個(gè)頁(yè)面會(huì)話的。而 OneAPM 相對(duì)來(lái)講,就更強(qiáng)大了,可以理解為云端 SaaS 版的 XHProf 和更強(qiáng)大的 SocketLog。不過(guò)有著更為強(qiáng)大的優(yōu)勢(shì)。比如:
-
OneAPM 的 PHP 探針,安裝完成之后,并不需要在代碼中埋入任何代碼。
-
在數(shù)據(jù)收集的過(guò)程中,不需要開(kāi)發(fā)和運(yùn)維的參與,探針全自動(dòng)收集,并提交到遠(yuǎn)程服務(wù)器。
-
由于數(shù)據(jù)累積,所以支持歷史報(bào)表,以及比 XHProf 和 SocketLog 更豐富的功能。
-
PHP 只是 OneAPM 所支持的一種語(yǔ)言,它可以支持多種語(yǔ)言,HTML5、 iOS 、 Android 、 Java 、 .NET 、 python 、 Node.js 、 PHP 、 ruby 等。
OneAPM 的安裝過(guò)程也比較簡(jiǎn)單,不過(guò)由于是 SaaS 服務(wù),所以得上官網(wǎng)注冊(cè)一個(gè)賬號(hào)。登錄了之后,在應(yīng)用程序里,點(diǎn)擊添加,再選中 PHP,就進(jìn)入了安裝探針的說(shuō)明。
分為如下幾步:
1. 獲取授權(quán)編號(hào)
OneAPM 授權(quán)憑證,用于配置和身份識(shí)別。
2. 下載 OneAPM PHP agent 安裝程序
3. 解壓 OneAPM PHP Agent
tar -xzf OneAPM_php_Agent_2.3.11.tar.gz
4. 安裝 OneAPM PHP Agent
-
定位路徑至您的安裝包所在文件夾
cd oneapm-php5-linux-install-script
-
執(zhí)行安裝命令
sudo ./oneapm-install install
5. 輸入 License Key
請(qǐng)點(diǎn)擊步驟1中的「生成授權(quán)編號(hào)按鈕」成功安裝,界面如下:
若出現(xiàn)以下信息,則代表安裝成功。
OneAPM is now installed on your system. Congratulations!
當(dāng)頁(yè)面出現(xiàn)以下提示時(shí),啟動(dòng) Daemon
And then start php-agent in /usr/bin/oneapm-daemon
運(yùn)行以下指令來(lái)啟動(dòng) Daemon
sudo /usr/bin/oneapm-daemon
重啟 Apache 或你使用的 web 調(diào)度程序 「如 php-fpm 」
6. 靜候5分鐘,開(kāi)啟 OneAPM 之旅
靜候5分鐘,等待應(yīng)用程序向 OneAPM 發(fā)送應(yīng)用程序性能數(shù)據(jù),即可開(kāi)始使用 OneAPM 應(yīng)用性能管理。
OneAPM 收集的數(shù)據(jù)很豐富。將收集的響應(yīng)時(shí)間數(shù)據(jù),分為四個(gè)大塊:
-
Web 事務(wù),就是頁(yè)面業(yè)務(wù)邏輯本身
-
數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)的連接和數(shù)據(jù)讀取
-
錯(cuò)誤統(tǒng)計(jì),對(duì)所有類型的錯(cuò)誤做了歸類統(tǒng)計(jì)
-
外部服務(wù),即外部 API 等的設(shè)備
以筆者的站點(diǎn)為例,12小時(shí)的數(shù)據(jù)如下圖:
從上面這個(gè)圖,我們看到響應(yīng)時(shí)間,慢的達(dá)到了600 ms 以上,那是什么導(dǎo)致的呢?我們可以分別查看:
可見(jiàn) Web 事務(wù)比較穩(wěn)定,可以比較清楚地看到平均的響應(yīng)時(shí)間在 50ms-75ms之間。
數(shù)據(jù)庫(kù)響應(yīng)時(shí)間也很短,在幾 ms 這個(gè)級(jí)別。而外部服務(wù)就明顯在幾百 ms 這個(gè)級(jí)別,還有的高達(dá) 600 ms 。
不說(shuō)別的,就通過(guò)這簡(jiǎn)單的報(bào)表,從目前看,就可以定位到,想要做優(yōu)化,從外部服務(wù)的響應(yīng)時(shí)間上下手優(yōu)化,帶來(lái)的效果是***的。
下面我們?cè)賮?lái)看看三個(gè)細(xì)化一層的報(bào)表 ,在 Web 事務(wù)統(tǒng)計(jì)中,盡管平均數(shù)很低,但是也列出了響應(yīng)時(shí)間最長(zhǎng)的5個(gè)請(qǐng)求。如下:
從上面的數(shù)據(jù)可以看出,響應(yīng)時(shí)間最長(zhǎng)的幾個(gè),主要突出在 bind.php
,這個(gè)是負(fù)責(zé) QQ 登錄的請(qǐng)求,需要向騰訊請(qǐng)求數(shù)據(jù)。
而在數(shù)據(jù)庫(kù)一欄中,可以看到最慢的5個(gè)表格的情況。
在外部的服務(wù)中,果不出所料,是對(duì)微博、微信、QQ 登錄、七牛上傳、支付寶通知等外部服務(wù),所占時(shí)間最長(zhǎng)。如下圖所示。
這只是普通的統(tǒng)計(jì)報(bào)表,對(duì)于具體的某一個(gè)慢的頁(yè)面,更有詳細(xì)的調(diào)用分析。
比如上面的 bind.php
,果真最慢的是從網(wǎng)絡(luò)上獲取數(shù)據(jù)。也就是說(shuō),第三方登錄時(shí),從第三方網(wǎng)站取數(shù)據(jù)花了絕大部分時(shí)間。 去查看詳情,有兩個(gè)不足之處,一是需要埋代碼,二是只是基于單獨(dú)一個(gè)頁(yè)面會(huì)話的。而 OneAPM 稱為慢事務(wù)追蹤,拉到頁(yè)面的***部就能看到。
在后臺(tái)報(bào)表中,我們同樣也能看到是哪些 SQL 語(yǔ)句慢。比如如下是 bind.php
中慢的 SQL 語(yǔ)句。
更為重要的是,還有所有錯(cuò)誤信息的收集,也一目了然。
所以無(wú)論從功能之強(qiáng)大,還是易用之方便,有兩個(gè)不足之處,一是需要埋代碼,二是只是基于單獨(dú)一個(gè)頁(yè)面會(huì)話的。而 OneAPM 不愧是商業(yè)化的 SaaS 服務(wù),比 XHProf 勝去了不少。在筆者的項(xiàng)目中,已經(jīng)大量使用。并取得了好的效果。
以上四個(gè)項(xiàng)目,讓我們對(duì)自己所寫的代碼,更加成竹在胸,無(wú)論是執(zhí)行過(guò)程還是調(diào)優(yōu)著手了都有了充分的把握。特意對(duì)比,匯總整理的這四大神器,希望它們能改善每一位 PHP 開(kāi)發(fā)者的生活,讓我們的 PHP 開(kāi)發(fā)不再那么地苦逼!