暫且不討論「PHP 是不是最好的編程語(yǔ)言」,本文我們將分別分析一下在 PHP 程序的后端外圍資源和前端外圍資源,它們對(duì)整個(gè) PHP Web 應(yīng)用體驗(yàn)的影響,這往往比語(yǔ)言本身大得多。
首先穷绵,后端外圍資源,是指跟 PHP 運(yùn)行過程中與語(yǔ)言本身無關(guān)的網(wǎng)絡(luò)與 IO 操作特愿、存儲(chǔ)服務(wù)仲墨、中間件代理勾缭、緩存和數(shù)據(jù)庫(kù)訪問等,在本文中目养,我們先分析 IO 操作和中間件服務(wù)俩由。
為什么外圍資源的性能分析,要以以上三者分析為主癌蚁?我們可以看如下國(guó)內(nèi)專業(yè)的性能監(jiān)控工具 OneAPM 的 PHP Web 應(yīng)用后臺(tái)截取下來的總覽圖幻梯,通過這個(gè)圖可以看到,數(shù)據(jù)庫(kù)所花費(fèi)的時(shí)間在總 PHP 響應(yīng)時(shí)間中努释,占據(jù)著 60% 甚至更大的比重碘梢,而 Memcached 緩存服務(wù),在這張圖里所占的響應(yīng)時(shí)間伐蒂,幾乎看不見煞躬。

下面正式開始。
一饿自、IO 操作
PHP 語(yǔ)言本身盡管有性能的差異汰翠,但是從對(duì) PHP 的性能微觀分析也可以看出龄坪,如果只執(zhí)行單次操作昭雌,實(shí)際中這種差別是非常小的,前面的實(shí)驗(yàn)中健田,十萬次以上操作烛卧,才有百 ms 級(jí)的差別,因?yàn)?PHP 語(yǔ)言本身操作的是內(nèi)存妓局,一次內(nèi)存訪問总放,大約在 50ns 左右。而 IO 操作好爬,則是磁盤訪問局雄,一次磁盤訪問所費(fèi)時(shí)間在 5ms 以上。僅從這個(gè)數(shù)量級(jí)看是 10 萬倍的差距存炮,實(shí)際上炬搭,根據(jù)實(shí)驗(yàn),也有百倍級(jí)的差距(順序訪問和隨機(jī)訪問差距巨大穆桂,實(shí)際中兩者同時(shí)進(jìn)行宫盔,還會(huì)有磁盤緩存等)。

所以對(duì)比語(yǔ)言本身享完,IO 成為瓶頸的可能性更大灼芭。首先看一下,IO 操作帶來的性能差別般又。
一個(gè) PHP 腳本彼绷,通過 PHP 命令方式運(yùn)行巍佑,正常時(shí),消耗時(shí)間如下:

當(dāng)使用如下命令清空磁盤緩存后:
echo 3 | sudo tee /proc/sys/vm/drop_caches
得到的第一次運(yùn)行時(shí)間下如下圖所示:

代碼一模一樣苛预,但是運(yùn)行時(shí)間卻是正常運(yùn)行時(shí)間的 6 倍句狼。當(dāng)然這個(gè)時(shí)間的慢,并不僅僅是由于程序本身的 IO 操作導(dǎo)致热某,而更大的慢的因素是在 CGI 模式下腻菇,PHP 腳本的每一次運(yùn)行都需要加載所有模塊,這個(gè)加載昔馋,也伴隨著大量的 IO 操作筹吐。
再做一個(gè)實(shí)驗(yàn),完全同樣功能的兩個(gè)頁(yè)面秘遏,一個(gè)采用了 MVC 的方式丘薛,把頭部,尾部拆開成獨(dú)立的模板(并未使用模板引擎)邦危,中間邏輯也使用獨(dú)立的 Model 類來處理洋侨。另一個(gè)只 require 了宏定義和數(shù)據(jù)庫(kù)操作兩個(gè)文件。
使用命令ab -c 40 -n 1000 http://xxxxx/0929/zuche/carlist.php
進(jìn)行壓力測(cè)試, 這兩個(gè)頁(yè)面運(yùn)行穩(wěn)定后壓測(cè)結(jié)果數(shù)據(jù)如圖所示倦蚪。


在這個(gè)頁(yè)面中希坚,MVC 版本所費(fèi)時(shí)間要多 6-8ms 左右。雖然只是多增加了幾個(gè)文件包含陵且,但是明顯增加了請(qǐng)求延時(shí)裁僧,如果文件操作本身更加復(fù)雜,比如文件上傳慕购、檢測(cè)聊疲、轉(zhuǎn)換,則延時(shí)會(huì)增加一個(gè)數(shù)量級(jí)以上沪悲。在實(shí)際的生產(chǎn)使用中获洲,也不是說有了文件操作,就一定會(huì)產(chǎn)生大的延時(shí)殿如,因?yàn)榫拖癖纠?require 而言贡珊,由于磁盤緩存等的存在,延時(shí)的影響已降低很多握截。
二飞崖、中間件代理
在正式使用中間件之前,我們先對(duì)比一下谨胞,使用數(shù)據(jù)庫(kù)與不使用數(shù)據(jù)庫(kù)的差別固歪,同樣是上面的這個(gè)例子,我們把數(shù)據(jù)結(jié)果集,從數(shù)據(jù)庫(kù)獲取轉(zhuǎn)換成為直接的結(jié)果數(shù)組設(shè)置牢裳,為了結(jié)構(gòu)化清楚逢防,采用 MVC 這一版。同時(shí)為了更顯著對(duì)比上一輪測(cè)試結(jié)果蒲讯,同時(shí)也消除語(yǔ)言本身的一些慢的因素忘朝,在本輪實(shí)驗(yàn)中,我們采用 PHP7判帮,得到結(jié)果是令人吃驚的局嘁。
如下圖是帶有數(shù)據(jù)庫(kù)連接和數(shù)據(jù)讀取的版本,PHP 擴(kuò)展使用的是 mysqli晦墙。

由于本頁(yè)面悦昵,只有一次數(shù)據(jù)庫(kù)操作,頁(yè)面結(jié)構(gòu)也比較簡(jiǎn)單晌畅,語(yǔ)言本身的影響因素非常大但指,PHP7 下速度有兩倍以上提升,原來平均響應(yīng)時(shí)長(zhǎng)為 37-40ms抗楔,現(xiàn)在則為 14ms棋凳。

即使如此,不讀取數(shù)據(jù)庫(kù)時(shí)连躏,有 4ms 的差距剩岳,盡管數(shù)目上不大,但是對(duì)于一個(gè)總響應(yīng)時(shí)長(zhǎng)只有 14ms 的應(yīng)用反粥,這 4ms 已經(jīng)很顯著了卢肃,而這只是一個(gè)數(shù)據(jù)庫(kù)查詢操作疲迂。
接下來看一下才顿,當(dāng)增加一層數(shù)據(jù)庫(kù)中間件時(shí),效率又有怎么樣的變化呢尤蒿?由于筆者所使用的中間件郑气,目前并不支持 PHP7,所以我們還在老版 PHP 的基礎(chǔ)上來比對(duì)腰池。在同樣的服務(wù)器壓力下尾组,使用了中間件的版本慢了一倍以上。如下圖所示示弓。

從這個(gè)例子可以看出來讳侨,原本 PHP 直接連數(shù)據(jù)庫(kù),取得數(shù)據(jù)的操作奏属,增加了中間件之后跨跨,變了先到中間件,中間件再到數(shù)據(jù)庫(kù),返回亦如是勇婴,導(dǎo)致了速度的大幅度下降(這里已經(jīng)剔除了中間件本身占用資源的因素忱嘹,在原來直連的版本是 37-40ms 左右)。
這里也請(qǐng)讀者不要誤解耕渴,演示中間件使用速度下降的例子拘悦,并不是說為了說明中間件不好,在分布式環(huán)境下橱脸,使用中間件是非常必要的础米。而是說,程序的外部資源添诉,往往是影響性能的重要因素椭盏,尤其是當(dāng)外部資源的連接和數(shù)據(jù)獲取本身速度達(dá)不到理想的結(jié)果時(shí)。
對(duì)于 IO 操作和中間件服務(wù)的分析就到這里吻商,下篇將分析數(shù)據(jù)庫(kù)給整個(gè)應(yīng)用性能帶來的影響掏颊。
OneAPM for PHP 能夠深入到所有 PHP 應(yīng)用內(nèi)部完成應(yīng)用性能管理和監(jiān)控,包括代碼級(jí)別性能問題的可見性艾帐、性能瓶頸的快速識(shí)別與追溯乌叶、真實(shí)用戶體驗(yàn)監(jiān)控、服務(wù)器監(jiān)控和端到端的應(yīng)用性能管理柒爸。