PHP 開發中的外圍資源性能分析
首先,後端外圍資源,是指跟 PHP 運行過程中與語言本身無關的網絡與 IO 操作、存儲服務、中間件代理、緩存和數據庫訪問等,在本文中,我們先分析 IO 操作和中間件服務。
為什麼外圍資源的性能分析,要以以上三者分析為主?我們可以看如下國內專業的性能監控工具 OneAPM 的 PHP Web 應用後台截取下來的總覽圖,通過這個圖可以看到,數據庫所花費的時間在總 PHP 響應時間中,占據著 60% 甚至更大的比重,而 Memcached 緩存服務,在這張圖裡所占的響應時間,幾乎看不見。
PHP 語言本身盡管有性能的差異,但是從對 PHP 的性能微觀分析也可以看出,如果只執行單次操作,實際中這種差別是非常小的,前面的實驗中,十萬次以上操作,才有百 ms 級的差別,因為 PHP 語言本身操作的是內存,一次內存訪問,大約在 50ns 左右。而 IO 操作,則是磁盤訪問,一次磁盤訪問所費時間在 5ms 以上。僅從這個數量級看是 10 萬倍的差距,實際上,根據實驗,也有百倍級的差距(順序訪問和隨機訪問差距巨大,實際中兩者同時進行,還會有磁盤緩存等)。
所以對比語言本身,IO 成為瓶頸的可能性更大。首先看一下,IO 操作帶來的性能差別。
一個 PHP 腳本,通過 PHP 命令方式運行
當使用如下命令清空磁盤緩存後:
echo 3 | sudo tee /proc/sys/vm/drop_caches代碼一模一樣,但是運行時間卻是正常運行時間的 6 倍。當然這個時間的慢,並不僅僅是由於程序本身的 IO 操作導致,而更大的慢的因素是在 CGI 模式下,PHP 腳本的每一次運行都需要加載所有模塊,這個加載,也伴隨著大量的 IO 操作。
再做一個實驗,完全同樣功能的兩個頁面,一個采用了 MVC 的方式,把頭部,尾部拆開成獨立的模板(並未使用模板引擎),中間邏輯也使用獨立的 Model 類來處理。另一個只 require 了宏定義和數據庫操作兩個文件。
使用命令ab -c 40 -n 1000 http://xxxxx/1229/redist/index.php 進行壓力測試,
在這個頁面中,MVC 版本所費時間要多 6-8ms 左右。雖然只是多增加了幾個文件包含,但是明顯增加了請求延時,如果文件操作本身更加復雜,比如文件上傳、檢測、轉換,則延時會增加一個數量級以上。在實 際的生產使用中,也不是說有了文件操作,就一定會產生大的延時,因為就像本例的 require 而言,由於磁盤緩存等的存在,延時的影響已降低很多。
在正式使用中間件之前,我們先對比一下,使用數據庫與不使用數據庫的差別,同樣是上面的這個例子,我們把數據結果集,從數據庫獲取轉換成為直接的結 果數組設置,為了結構化清楚,采用 MVC 這一版。同時為了更顯著對比上一輪測試結果,同時也消除語言本身的一些慢的因素,在本輪實驗中,我們采用 PHP7,得到結果是令人吃驚的。 如下圖是帶有數據庫連接和數據讀取的版本,PHP 擴展使用的是 mysqli。
由於本頁面,只有一次數據庫操作,頁面結構也比較簡單,語言本身的影響因素非常大,PHP7 下速度有兩倍以上提升,原來平均響應時長為 37-40ms,現在則為 14ms。
即使如此,不讀取數據庫時,有 4ms 的差距,盡管數目上不大,但是對於一個總響應時長只有 14ms 的應用,這 4ms 已經很顯著了,而這只是一個數據庫查詢操作。
接下來看一下,當增加一層數據庫中間件時,效率又有怎麼樣的變化呢?由於筆者所使用的中間件,目前並不支持 PHP7,所以我們還在老版 PHP 的基礎上來比對。在同樣的服務器壓力下,使用了中間件的版本慢了一倍以上。如下圖所示。
從這個例子可以看出來,原本 PHP 直接連數據庫,取得數據的操作,增加了中間件之後,變了先到中間件,中間件再到數據庫,返回亦如是,導致了速度的大幅度下降(這裡已經剔除了中間件本身占用資源的因素,在原來直連的版本是 37-40ms 左右)。
這裡也請讀者不要誤解,演示中間件使用速度下降的例子,並不是說為了說明中間件不好,在分布式環境下,使用中間件是非常必要的。而是說,程序的外部資源,往往是影響性能的重要因素,尤其是當外部資源的連接和數據獲取本身速度達不到理想的結果時。
對於 IO 操作和中間件服務的分析就到這裡,下篇將分析數據庫給整個應用性能帶來的影響。
*