解決PHP Opcache 快取重新整理、程式碼重載出現無法更新程式碼的問題
問題背景
通過啟用Opcache的快取優化,將PHP程式碼預編譯為Opcode快取到共享記憶體中供程序反覆呼叫,從而減少了重複從磁碟解析PHP程式碼的時間消耗,顯著的提高了PHP效能,提升了業務效能的呼叫,但是也引發了一些問題,就是我們每次更新了相應的PHP程式碼後,web server 無法即時載入到更新後的程式碼。
解決方案
(一)、設定Opcache指令碼驗證時間
可以通過更改 Opcache 以下兩個配置選項來調整程式碼過載時間
opcache.revalidate_freq=0 檢查指令碼時間戳是否有更新的週期,以秒為單位。(如果設定為 0 會導致針對每個請求, OPcache 都會檢查指令碼更新)
opcache.validate_timestamps=0 如果啟用,那麼 OPcache 會每隔 opcache.revalidate_freq 設定的秒數 檢查指令碼是否更新。
PS:在實際生產環境中,為了儘可能達到最優效能,儘量不開啟檔案更新驗證,因為每次驗證都會重新預編譯PHP程式碼到共享記憶體中。
(二)、重啟 | 過載 php-fpm 程序
每次重啟或重啟 php-fpm 程序便會重新解析PHP指令碼檔案,但是重啟 fpm 程序可能會導致請求中斷,從而導致寫入髒資料 或者 造成事務回滾等一系列異常。
過載相對於重啟則平順很多,不會導致使用者請求直接中斷,相對來說風險低很多,但是php-fpm 收到reload訊號,便會向所有子程序傳送SIGGUIT訊號,同時註冊一個定時器,在規定的時間之內子程序沒有退出,接著在傳送SIGTERM訊號,結束子程序。如果在一秒之內子程序還是沒結束 直接傳送SIGKILL 強制殺死。
重啟php-fpm
service php-fpm restart
過載php-fpm
services php-fpm reload 或 kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`
(三)、手動清理快取
除了上面的兩種方式,還有更為穩妥一點的快取清理,我們可以通過opcache_reset()和opcache_invalidate() 函式來重新整理Opcache快取。
opcache_reset()
- 重置整個Opcode快取,所有的PHP指令碼將會被重新解析再預編譯為Opcode。
opcache_invalidate()
需要注意的是,當PHP以PHP-FPM的方式執行的時候,opcache的快取是無法通過php命令進行清除的,只能通過http或cgi到php-fpm程序的方式來清除快取,我們可以編寫一個對外介面,來達到清理快取的目的。
相關實現如下(框架:laravel):
Route::any('cache-reset',function () { //重置整個Opcode快取 dd(opcache_reset()); }); Route::any('cache-update',function () { //清除掉最近一次更新檔案的快取 exec('git diff --name-only HEAD~ HEAD',$output); foreach ($output as $file) { $path = base_path($file); opcache_invalidate($path,true); } dd('重新整理完成'); });
總結
通過上面的三種策略,可以實現 Opcache 快取更新的目的,但是在流量高峰期或者大流量的服務端,每次更新快取都是一件非常損耗資源的事情,Opcache在重建快取時,也不會禁止其他程序讀取,因此就會造成反覆新建快取,因此想要達到最佳的效能調配:
- 最好不要在高峰期清理快取
- 高峰期不要頻繁的更新程式碼,清理快取,會造成重複新建快取
- 如果需要更新,可以嘗試削弱服務端權重,實現逐個更新的目的。
- 如果需要強制更新,儘量選擇手動清除快取的方式,來重建Opcache快取,使代價最小化。
以上就是解決PHP Opcache 快取重新整理、程式碼重載出現無法更新程式碼的問題的詳細內容,更多關於PHP Opcache 快取重新整理、程式碼過載的資料請關注我們其它相關文章!