使用OPCache提升PHP的性能
對于 PHP 這樣的解釋型語言來說,每次的運作都會将所有的代碼進行一次加載解析,這樣一方面的好處是代碼随時都可以進行熱更新修改,因為我們不需要編譯。但是這也會帶來一個問題,那就是無法承載過大的通路量。畢竟每次加載解析再釋放,都會增加 CPU 的負擔,通常一台 8核16G 的伺服器在2、3000并發左右 CPU 就能達到60%以上的使用率。而且如果你使用的是類似于 Laravel 這種大型的架構,效率将更加低下。這個時候,我們通常會通過增加伺服器數量來做負載均衡,進而達到減輕伺服器壓力的效果。不過,這樣做的成本又會增加許多。那麼,有沒有什麼優化的方案呢?
鳥哥在他的部落格中針對 PHP7 的優化的一篇文章中,第一條建議就是開啟 OPcache 。當然,另外一個方案就是使用 Swoole 。關于 Swoole 的内容我們将來再說,今天,我們先學習學習 OPcache 。
什麼是 OPcache
OPcache 通過将 PHP 腳本預編譯的位元組碼存儲到共享記憶體中來提升 PHP 的性能, 存儲預編譯位元組碼的好處就是 省去了每次加載和解析 PHP 腳本的開銷。
這是 PHP 文檔中關于 OPcache 的簡介,也就是說,OPcache 節約了每次加載和解析的步驟,将第一次解析編譯後的腳本位元組碼緩存到系統的共享記憶體中。其實,這就類似于一個不完全的編譯。
類似于 Java 之類的語言,都是要打包編譯之後才能上線運作的,比如打包成一個 jar包 。C++ 或 C# 可以打包成一個 .dll 或 .exe 。這些打包之後的檔案就是編譯完成的檔案,将它們運作起來後一般會一直保持運作狀态,也就是會成為一個常駐程序,它們的代碼就進入記憶體中了。在程式運作的時候,不需要再進行解釋或編譯,自然速度就要快很多。而 OPcache 也是起到類似的作用。隻不過它并不是完全的一套編譯流程,我們還是依賴的 PHP-FPM 來運作腳本,隻不過在開啟 OPcache 後,PHP-FPM 會先從記憶體中查找是否已經有相關的已經緩存的位元組碼在記憶體中了,如果有的話就直接取用,如果沒有的話,會再次進行解釋編譯後緩存下來。另外,OPcache 是針對檔案的,也就是說,一個檔案如果是新增加進來的,隻有運作過它才會緩存,如果沒有運作過,它并不在目前的共享記憶體中。
安裝 Opcache
OPcache 已經是 PHP 的官方擴充并随安裝包一起釋出了,是以,我們可以在編譯安裝 PHP 時使用 --enable-opcache 來開啟擴充,它已經是預設擴充。也可以在未安裝 OPcache 的系統中使用安裝包中的檔案來進行安裝。
cd php-7.4.4/ext/opcache/
phpize
./configure
make && make install
複制
需要注意的是, OPcache 和 Xdebug 在生産環境中盡量不要一起使用。本身 Xdebug 就是不推薦在生産環境中使用的,如果一定需要同時使用的話,需要先加載 OPcache ,然後再加載 Xdebug 。
擴充安裝後,在 php.ini 檔案中打開擴充。需要注意的是,OPcache 擴充是 Zend 擴充包,是以我們需要打開的是 Zend 擴充。
zend_extension=opcache.so
複制
另外,還需要啟用它。
opcache.enable=1
複制
當開啟了 OPcache 之後,我們再更新代碼将會發現剛剛更新的代碼不是我們最新的代碼。這是因為代碼已經被緩存了,就像 Java 一樣,我們需要重新開機服務才行。那麼 PHP 這邊重新開機的是什麼呢?當然就是重新開機下我們的 PHP-FPM 就可以了,直接使用 kill -USR2 指令去重新開機主程序就行了。這裡也給出一個快速重新開機的指令。
ps -ef | grep "php-fpm: master" | grep -v grep | cut -c 9-15 | xargs kill -USR2
複制
ab 測試效果
我們進行測試的内容是測試環境的一台2核4G的伺服器,使用的 PHP 版本是 PHP7.4 ,正常的 Nginx 及 PHP 配置, ulimit 也都開到了最大。代碼隻是簡單的輸出了一行文字,不過我們使用的是一個簡單的 mvc 架構 ,也就是說這段代碼運作起來至少也會加載幾個檔案,而不是簡簡單單的一個檔案。
首先我們來看未開啟 OPcache 的情況。
接下來是開啟了 OPcache 的情況。
很明顯,性能有了很大的提高。不僅速度快了很多,吞吐率也是直接上升了幾倍。當然,這隻是非常簡單的一個測試,不過總體看來,确實對單機的性能提升有很大的幫助。最最主要的是,同樣的并發情況下,CPU 資源也比未開啟的狀态下低了70%。
配置參考
在 PHP 的官方文檔中,已經為我們給出了一套預設的 OPcache 在 php.ini 中的配置。經過測試,基本沒什麼問題,當然,現在還沒有在生産環境中使用過,還需要進行更多的測試。不過文檔中指出,這套配置是可以直接運用到線上的,不過需要注意的是某些使用了注解之類功能的進階架構可能需要注意某些參數。
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1
複制
具體的配置說明以及其他的一些配置選項我們可以參考官方文檔進行詳細的了解。
總結
既然是我們的 PHP 大神鳥哥推薦的,而且也是官方推薦的擴充,我覺得在正式生産環境中使用不會有太大問題。另外,官方也給出了一套可以直接運用于線上生産環境的配置參數,也友善我們直接線上上進行測試。目前在生産環境中,我們隻使用了一台伺服器來進行測試,并且給它多配置設定了一些負載過來,從目前的情況來看,這一台機器的運作效率比其他幾台的高很多。因為它一方面處理了更多的請求,另一方面它的 CPU 資源占用率還沒有其他幾台機器高。同時,OPcache 也不需要我們去了解更多的程序協程之類的知識,不像 Swoole 一樣的會帶來更高的學習成本。是以綜上所述,在測試完備的情況下,OPcache 絕對是我們最優先考慮的單機優化方案。
參考文檔:
https://www.laruence.com/2015/12/04/3086.html
https://www.php.net/manual/zh/book.opcache.php