1. 程式人生 > 其它 >解決Nginx Helper外掛一鍵清理快取功能導致網站打不開問題

解決Nginx Helper外掛一鍵清理快取功能導致網站打不開問題

5 月份,張戈部落格分享了一篇《Nginx 開啟 fastcgi_cache 快取加速,支援 html 偽靜態頁面》的文章。文中也提到了 WordPress 有一款名為 Nginx Helper 的外掛是這個功能的絕佳搭配。

一、問題描述

不過,最近通過朋友反饋及我自己親測發現了一個嚴重的問題:

Nginx Helper 設定介面有一個一鍵清理快取的按鈕【Purge Entire Cache】,只要在後臺點選這個按鈕,前臺就跪了。當然,如果對登入使用者不顯示快取,那麼登入使用者訪問是正常的。

二、分析原因

分析了一下原因:【Purge Entire Cache】這個按鈕按下後會刪除 Nginx 所有的快取,但是卻不會過載(啟)Nginx。那麼問題來了,當在前臺請求需要展示快取的頁面時,Nginx 將繼續呼叫之前的快取檔案,然而所有快取檔案卻被這個外掛刪除了,所以這個頁面就 502 了!

清理前可以看到如圖快取資料夾:

但是清理後,就沒了,而且也不會在生成。因為這樣強行全部刪除並沒有“通知”Nginx ...這時候,網站就打不開了。當然,如果是設定了登入使用者或已評論使用者不展示快取,那麼網站會實時展示正常開啟。但是要展示快取頁面就會 502 了,因為 Nginx 自己都找不到路徑了。。。

三、部署解決

不難理解,要解決這個問題,比如給一鍵清理功能繫結一個過載 Nginx 的機制。但是一般情況下 php 並沒有許可權去過載或重啟 Nginx 。所以,要繼續使用這個一鍵清理功能,就只能授予 php 重啟 Nginx 的許可權,還需要將重啟 Nginx 的命令整合到外掛才行。

①、授權 php 執行系統命令

php 重啟 nginx 功能,張戈部落格之前已經分享過相應的辦法了,請先參考部署該功能:

php 平滑重啟 nginx,徹底清除 WordPress 的靜態快取

②、將過載命令加入到一鍵清理函式

部署 OK 之後,編輯 Nginx helper 外掛下的 purger.php 檔案,找到如下函式:

function true_purge_all(){
	$this->unlinkRecursive(RT_WP_NGINX_HELPER_CACHE_PATH, false);
	$this->log( "* * * * *" );
	$this->log( "* Purged Everything!" );
	$this->log( "* * * * *" );
	}

如下在函式中新增過載 nginx 的程式碼即可:

function true_purge_all(){
	$this->unlinkRecursive(RT_WP_NGINX_HELPER_CACHE_PATH, false);
	exec(EscapeShellCmd("/opt/reload_nginx.sh"));//一鍵清理後重載nginx
	$this->log( "* * * * *" );
	$this->log( "* Purged Everything!" );
	$this->log( "* * * * *" );
	}

好了,現在點選一鍵清理功能,快取會全部刪除,而且 nginx 也會過載,前臺網站也就不會跪了。

四、其他完善

當然,經常有人反饋偶爾更新文章,前臺並不會重新整理。其實,這本文陳述的情況也有關係。在使用【刪除模式】時,單篇文章的快取被清理後,也不會過載 Nginx。此時,如果此文的快取是存放在記憶體的話,前臺肯定就不會重新整理了!

所以,我們有必要給單個清理功能也繫結一個過載 Nginx 的機制。此處為了節省數千個字,張戈決定提供全部修改好的 Nginx Helper 外掛,需要的自行下載重新安裝這個外掛即可:

下載地址

你可能會疑問為毛刪除單個頁面後,這個頁面卻還能開啟?和刪除全部不是一樣的機制嗎?

分析了下,如果類比刪除全部快取帶來的問題,刪除單個頁面應該也會出現該頁面打不開的情況才對。不過,細想了一下,解釋很簡單。因為刪除全部快取會破壞快取的檔案目錄結構,而刪除單個頁面只是刪除一個快取檔案,快取的目錄結構並未被破壞。

通俗來說:快取的目錄結構如同 Nginx 的一個行車路線,只有不破壞這個路徑,才能正常行駛。當然了,你破壞了這個行車路線,過載一下 Nginx 它又能重新規劃了。

五、更多花絮

當我發現這個問題,並解決後,還給這外掛的作者發了 BUG 反饋郵件。蹩腳的中式英語並不影響交流,哈哈!

感興趣的可以湊合看看:

Hello Zhang Ge, Thanks for contacting us. This is Dinesh from rtCamp. Sorry to hear about the problem you are facing. Please verify if the Nginx Helper plugin is properly configured from its settings page. As you are using Nginx FastCGI caching and the site is not loading after purging entire cache so I will suggest to try Redis cache. You can configure Redis cache option in Nginx Helper plugin once its enabled on server. Redis cache support "Custom Purge URL" option so you can add links which you want to purge instead of purging entire cache. Also, reloading of Nginx is not needed for purging cache. Please feel free to post your query if you are facing any problem on our community support forum (http://community.rtcamp.com/c/wordpress-nginx). Regards, Dinesh Hello , rtcamp: I found a bug with your plugin that named nginx-helper. When we click zhe Button [Purge Entire Cache], our websites  will dead immediately. Because  [Purge Entire Cache] will clean up all of the fastcgi cache,but without reload the nginx . So nginx can't find the cache when we request. To fixed the bug, you could added a action of reload nginx when [Purge Entire Cache] be clicked. FYI : exec(EscapeShellCmd("/opt/reload_nginx.sh")); But,it must supported by Operating environment. My post url: http://zhangge.net/5042.html ------------------ 張戈部落格是關注網際網路以及分享 IT 運維工作經驗的個人部落格,由系統運維、指令碼程式設計以及資源分享等分類組成,涵蓋了作業系統教程、運維經驗、指令碼語言以及網路資源等。 永久地址:http://zhangge.net Dinesh Jain | Project Manager | rtCamp Solutions Pvt. Ltd. Web: http://rtCamp.com | Skype: dinesh.jain.rtcamp | Twitter: @dineshjain2911

他要我去他們的論壇發帖,一起交流問題。好吧,我就去看了下,並簡單的陳述了一下問題和建議,結果並沒有什麼卵用,因為沒人回覆【帖子傳送門】。。。

最後,寫這篇文章時,我還是單獨給這哥們又發了一份郵件:

Dear Dinesh , Tks for your reply! I try to post the problem at bbs as your give,but nobody rebply(http://community.rtcamp.com/t/website-will-dead-when-we-click-the-button-purge-entire-cache/5052),so send a email to you again... Certainly,switch to "redis cache" is a good idea. But I use Nginx Fascgi Caching for a long time, because of it's simple. furthermore, redis is not installed on my webserver. Except for the solution I mentioned in my email. The function of "Purge all cache" should be hiddenwhen then plugin used Nginx-Fascgi-caching and set with "Delete local server cache files " method. Only in this way, the problem will not be triggered by someone who know nothing about this case. Of course, This problem should be gone when used "Uses the ngx_cache_purge module".... Regards, Jager

問題你不解決沒關係,但至少應該把這個功能隱藏或加上警告吧?這也是對外掛使用者負責的表現,否則很多不知情的人一點選一鍵清理後,前臺就歇菜了!多麼驚恐,誰還敢用。。。。

好了,如果你也存在這個問題,可以參考本文折騰一下。改了半天外掛,發現這個外掛並不複雜,後續有空自己寫幾段 PHP 程式碼就可以替換掉了。


2016-01-24 最新補充:突然想明白了一件事,其實一鍵清理可以不出現本文提到的問題!那就是定義 nginx 快取路徑是最多使用兩級目錄,而不能多於兩級。

比如,我之前的文章定義的 Nginx 快取目錄都使用了 /tmp/cache/wpcache,這種就是多於兩級目錄了,Nginx-Heper 刪除的時候會直接刪除這個路徑,如果不過載 Nginx 就不會重新生成目錄結構,將導致網站打不開!

簡單分析原因,應該是類似於 mkdir 是否帶 -p 引數的結果,如果 mkdir 要建立多級目錄,中間目錄不存在時必須加入 -p 才能成功建立!類比到 Nginx 的快取,它就沒有用到 -p 這種機制,如果多級目錄,中間目錄不存在,它就傻眼了!

如果是定義成一級或二級目錄,比如使用 /tmp/wpcache 就不會出現這個問題,具體原因就不做分析了!大家如果參考了張戈部落格之前寫的 Nginx 快取配置,請將快取檔案的路徑都修改為二級即可,比如 /tmp/wpcache 。