OPcache通過(guò)opcode的緩存和優(yōu)化,提供更快的PHP執(zhí)行過(guò)程。
業(yè)務(wù)在php7環(huán)境運(yùn)營(yíng)時(shí),為了提升請(qǐng)求的性能,在PHP7環(huán)境中配置OPcache擴(kuò)展。
業(yè)務(wù)在更新代碼后,訪問(wèn)業(yè)務(wù)系統(tǒng)時(shí)提示無(wú)法找到對(duì)應(yīng)的文件或請(qǐng)求的內(nèi)容還是更新前的舊內(nèi)容,
webserver重啟以后,請(qǐng)求訪問(wèn)到的文件就都是最新的了,問(wèn)題就貌似解決了。
根據(jù)現(xiàn)象分析,代碼更新后請(qǐng)求找不到新增的文件,尤其是還在請(qǐng)求已有文件更新前的內(nèi)容,那么可能跟緩存有關(guān)系,考慮到跟業(yè)務(wù)代碼邏輯無(wú)關(guān),關(guān)閉opcache的配置問(wèn)題就不再出現(xiàn),基本上可以定位到問(wèn)題出在opcache的配置上。
cat /usr/local/php/etc/subconfig/opcache.inizend_extension=opcache.soopcache.enable=1opcache.revalidate_freq=0opcache.validate_timestamps=0opcache.max_accelerated_files=7963opcache.memory_consumption=192opcache.interned_strings_buffer=16opcache.fast_shutdown=1opcache.enable_cli=1
opcache.enable 啟用操作碼緩存,默認(rèn)為“1”
如果禁用此選項(xiàng),則不會(huì)優(yōu)化和緩存代碼。 在運(yùn)行期使用 ini_set() 函數(shù)只能禁用 opcache.enable 設(shè)置,不可以啟用此設(shè)置。 如果在腳本中嘗試啟用此設(shè)置項(xiàng)會(huì)產(chǎn)生警告。
opcache.enable_cli 僅針對(duì) CLI 版本的 PHP 啟用操作碼緩存。
通常被用來(lái)測(cè)試和調(diào)試。
opcache.revalidate_freq=0 檢查腳本時(shí)間戳是否有更新的周期,以秒為單位。
設(shè)置為 0 會(huì)導(dǎo)致針對(duì)每個(gè)請(qǐng)求, OPcache 都會(huì)檢查腳本更新。
opcache.validate_timestamps=0 如果啟用,那么 OPcache 會(huì)每隔 opcache.revalidate_freq 設(shè)定的秒數(shù) 檢查腳本是否更新。
如果禁用此選項(xiàng),你必須使用 opcache_reset() 或者 opcache_invalidate() 函數(shù)來(lái)手動(dòng)重置 OPcache,也可以 通過(guò)重啟 Web 服務(wù)器來(lái)使文件系統(tǒng)更改生效。
最初的配置是:
opcache.revalidate_freq=60,opcache.validate_timestamps=1
即每60秒檢測(cè)一次更新字節(jié)碼緩存,業(yè)務(wù)代碼更新后可能需要60秒以后才能訪問(wèn)到最新的內(nèi)容,也就出現(xiàn)了最初訪問(wèn)不到新增的內(nèi)容。
php代碼的更新方式有兩種,一種是覆蓋webserver配置的目錄下的文件來(lái)更新,一種是每次都部署一個(gè)全量包目錄,然后軟鏈接到webserver指定的目錄。
第一種覆蓋更新的方式,如果使用在過(guò)期時(shí)間后自動(dòng)清理opcache緩存內(nèi)容的話,更新操作如果有延遲,就會(huì)出現(xiàn)新舊代碼文件混合在一起的情況。
第二種全量包目錄發(fā)布后,軟鏈接到webserver指定路徑的方式,雖然不會(huì)存在新舊文件混合的問(wèn)題,但是在未自動(dòng)清理時(shí),即便webserver已經(jīng)鏈接到webserver對(duì)應(yīng)目錄,業(yè)務(wù)訪問(wèn)的還是舊文件。
目前使用rsync同步目錄文件的方式是我們更新代碼的主要方式,最初使用每60s定時(shí)清理opcache的緩存文件,在60s內(nèi)更新的文件不會(huì)生效,就導(dǎo)致了業(yè)務(wù)反饋代碼更新后訪問(wèn)不到的問(wèn)題。
使用定時(shí)更新代碼緩存的問(wèn)題,還有更新文件較多時(shí),代碼文件發(fā)布的過(guò)程中緩存發(fā)生更新,將會(huì)有60s新舊文件的緩存混合存在的問(wèn)題。
根據(jù)相關(guān)研究人員推薦,如果采用覆蓋更新代碼文件時(shí),更新操作完畢后,手動(dòng)清理緩存比較合適。
opcache.validate_timestamps=0
即,將oopcache.validate_timestamps設(shè)置為0。
配置了opcache.validate_timestamps值為0,必須手動(dòng)清空Z(yǔ)end OPcache緩存的字節(jié)碼,才能訪問(wèn)到最新的文件內(nèi)容。適合在生產(chǎn)環(huán)境中設(shè)置為0,但在開(kāi)發(fā)環(huán)境會(huì)帶來(lái)不便,可以在開(kāi)發(fā)環(huán)境中這樣配置啟用自動(dòng)驗(yàn)證緩存功能:
opcache.validate_timestamps=1
opcache.revalidate_freq=0
除了重啟php-fpm的進(jìn)程可以清理opcache緩存外,
手動(dòng)清理緩存涉及到的opcache函數(shù)主要為:opcache_reset()和opcache_invalidate() 。
boolean opcache_reset ( void ) 該函數(shù)將重置整個(gè)字節(jié)碼緩存。 在調(diào)用 opcache_reset() 之后,所有的腳本將會(huì)重新載入并且在下次被點(diǎn)擊的時(shí)候重新解析。
需要注意的是,當(dāng)PHP以PHP-FPM的方式運(yùn)行的時(shí)候,opcache的緩存是無(wú)法通過(guò)php命令進(jìn)行清除的,只能通過(guò)http或cgi到php-fpm進(jìn)程的方式來(lái)清除緩存。
In some (most?) systems, PHP‘s CLI has a separate opcode cache to the one used by the web server , or PHP-FPM process,which means running opcache_reset() in the CLI, won‘t reset the webserver/fpm opcode cache, and vice-versa.
曲線救國(guó),使用命令行清理php-fpm的opcache緩存:
#!/bin/bashcgi-fcgi -v > /dev/null 2>&1|| yum --enablerepo=epel install fcgi -y > /dev/null 2>&1echo ‘<?php opcache_reset(); echo "ok\n";‘ > /tmp/php-fpm-opcache-reset.php; SCRIPT_FILENAME=/tmp/php-fpm-opcache-reset.php REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000; rm -f /tmp/php-fpm-opcache-reset.php;
opcache_invalidate 廢除指定腳本緩存
boolean opcache_invalidate ( string $script [, boolean $force = FALSE ] ) 該函數(shù)的作用是使得指定腳本的字節(jié)碼緩存失效。 如果 force 沒(méi)有設(shè)置或者傳入的是 FALSE,那么只有當(dāng)腳本的修改時(shí)間 比對(duì)應(yīng)字節(jié)碼的時(shí)間更新,腳本的緩存才會(huì)失效。 參數(shù) script 緩存需要被作廢對(duì)應(yīng)的腳本路徑 force 如果該參數(shù)設(shè)置為T(mén)RUE,那么不管是否必要,該腳本的緩存都將被廢除。
opcache_invalidate可以針對(duì)單個(gè)或幾個(gè)腳本進(jìn)行來(lái)清理緩存。
總結(jié)
如果代碼發(fā)布是全量發(fā)布,切換軟鏈接的方式,可以設(shè)置opcache.validate_timestamps=1和opcache.validate_timestamps=1來(lái)定時(shí)自動(dòng)更新緩存。
如果代碼發(fā)布是覆蓋更新舊目錄,則可以重啟php-fpm及在腳本中或代碼文件中使用opcache_reset函數(shù)來(lái)清理所有緩存。
如果可以獲取到更新的代碼文件列表,則可以使用opcache_invalidate函數(shù)來(lái)清理代碼,同時(shí)也可以避免影響到其他業(yè)務(wù)的緩存。
如對(duì)本文有疑問(wèn),請(qǐng)?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會(huì)為你解答?。?點(diǎn)擊進(jìn)入論壇