PHP 效能優化 - OPcache

心智極客發表於2019-11-08

原理

首先,來看看 PHP 程式碼的執行過程:

  1. Lexing - 將 PHP 程式碼轉換為語言片段 (Tokens)
  2. Parse - 將 Tokens 轉換成簡單而有意義的表示式
  3. Compile - 將表示式編譯成位元組碼(OpCode)
  4. Excute - 順次執行位元組碼,每次一條,從而實現 PHP 指令碼的功能。

從執行步驟中可以看出,如果可以快取位元組碼的話,就可以跳過前面的步驟,從而大大提高 PHP 應用的效能。

PHP 效能優化 - OPcache

OPcache

在 PHP 5.5 之前,不少擴充套件都實現了位元組碼的快取,比如 Zend 公司開發的 Zend Optimizer Plus。該擴充套件也隨著 PHP 5.5 一起釋出,並改名為 OPcache。也就是說,從 5.5 開始,OPcache 成了 PHP 的預設繫結擴充套件。該擴充套件通過將 PHP 指令碼預編譯的位元組碼儲存到共享記憶體中,省去了每次載入和解析 PHP 指令碼的開銷。

引數說明

OPcache 擴充套件可通過 php.ini 來進行配置,以下是一些常用的配置引數說明,後面對應的預設值。

opcache.memory_consumption = 128

分配的記憶體大小,如果應用的指令碼數較少的話,可適當調小。

opcache.interned_strings_buffer = 8

儲存預留字串的記憶體大小。PHP 直譯器在背後會找到相同字串的多個例項,把這個字串儲存在記憶體中,如果再次使用相同的字串,PHP 直譯器會使用指標。這麼做能節省記憶體。預設情況下,PHP 駐留的字串會隔離在各個 PHP 程式中。這個設定能讓 PHP-FPM 程式池中的所有程式把駐留字串儲存到共享的緩衝區中,以便在 PHP-FPM 程式池中的多個程式之間引用駐留字串。

opcache.max_accelerated_files = 10000

OPcache 雜湊表中可儲存的指令碼檔案數量上限。該值的設定要大於應用的檔案數量。

opcache.validate_timestamps = 1

該選項的值為 1 或者 0, 1 代表啟用,一旦啟用該項, OPcache 會每隔 revalidate_freq 設定的秒數來檢查指令碼是否更新,開發環境下,一般將其設定為 1。而生產環境下,一般將其設定為 0,然後通過重啟 Web 伺服器或者使用 PHP 提供的 opcache_reset() 或者 opcache_invalidate() 函式來手動重置 OPcache。

revalidate_freq = 2

指令碼更新的檢查時間週期,一旦將該值設定為 0,那麼每個請求 OPcache 都會檢查指令碼更新。由於生產環境下的 validate_timestamps 通常設定為 0,所以該值往往只在開發環境下有意義。

enable_cli = 0 

僅針對 CLI 版本的 PHP 啟用操作碼快取,預設不開啟。

推薦配置

以下是 PHP 官方的推薦設定

opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.enable_cli=1

以下是 《Modern PHP》一書的推薦配置

opcache.memory_consumption=64
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=4000
opcache.revalidate_freq=0
opcache.validate_timestamps  開發環境為 1,生產環境為 0

相關函式

說明

PHP 官方提供了與 OPcache 相關的函式

opcache_compile_file ( string $file ) : boolean

該函式可以用於在不用執行某個 PHP 指令碼的情況下,編譯該 PHP 指令碼並將其新增到位元組碼快取中去。 該函式可用於在 Web 伺服器重啟之後初始化快取,以供後續請求呼叫。

opcache_get_configuration ( void ) : array

該函式將返回快取例項的配置資訊。

opcache_get_status ([ boolean $get_scripts = TRUE ] ) : array

該函式將返回快取例項的狀態資訊。

opcache_invalidate ( string $script [, boolean $force = FALSE ] ) : boolean

該函式的作用是使得指定指令碼的位元組碼快取失效。 如果 force 沒有設定或者傳入的是 FALSE,那麼只有當指令碼的修改時間 比對應位元組碼的時間更新,指令碼的快取才會失效。

opcache_is_script_cached ( string $file ) : bool

該函式用於檢測 PHP 指令碼是否已經被快取。

opcache_reset ( void ) : boolean

該函式將重置整個位元組碼快取。 在呼叫 opcache_reset() 之後,所有的指令碼將會重新載入並且在下次被點選的時候重新解析。有網友指出,該函式在 Cli 模式下不會生效。

應用

利用這些函式,可以方便的清空 OPcache 快取,比如將其封裝成指令碼,在程式碼更新後自動執行指令碼

#!/bin/bash
WEBDIR=/var/www/html/
RANDOM_NAME=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13)
echo "<?php opcache_reset(); ?>" > ${WEBDIR}${RANDOM_NAME}.php
curl http://localhost/${RANDOM_NAME}.php
rm ${WEBDIR}${RANDOM_NAME}.php

或者說利用這些函式來建立視覺化操作皮膚。例如,opcache-status 專案是一個展示 Opcache Status 的單個頁面,可以很方便的部署在自己的伺服器上。以下本地檢視的流程

$ git clone https://github.com/rlerdorf/opcache-status.git --depth=1
$ cd opcache-status
$ php -S localhost:8000 opcache.php

頁面顯示效果

PHP 效能優化 - OPcache

參考資料

微訊號 larahacks ,歡迎大家與我交流,請備註來意

相關文章