使用fastcgi_cache加速你的Nginx網站
很久以前在TW上挖了個坑,說nginx的fastcgi_cache是被大家忽視的一大金礦,今天把這個坑填上。
對于變化不太頻繁的數據,大家都比較喜歡存Memcached以減少數據庫的讀取,但還是會有語言解析運行上的消耗(比如運行PHP,Python等),當然這個時間很短,記得OP上有個同學說P字頭的語言,效率都不高,如果能省去,當然最好。(已經用上Squid等的可以忽略本文)。
還有一個問題就是很多時候一個頁面由多個數據片斷組成,為了提高頁面速度,要么分別緩存,要么整體緩存(所謂的Page Cache),其實都比較麻煩,增加和減少數據片斷的時,大多需要調整。
最后一個問題,所有的數據都存Memcached是否經濟?服務器資源足夠多的無所謂,捉襟見肘的就要考慮了,當然,生成靜態頁面是一種方法,需要維護,還是比較累。
好吧,nginx的fastcgi_cache可以解決上面的那些問題,比較squid等的好處是簡單,不需再要去維護另外一個系統,適合不那么大的網站。
關于Nginx fastcgi_cache,基礎的可以參看Nginx官方文檔http://wiki.nginx.org/HttpFcgiModule,下面是一個典型的做法是:
fastcgi_cache_path /data/ngx_fcgi_cache levels=2:2 keys_zone=ngx_fcgi_cache:512m inactive=1d max_size=40g;
fastcgi_cache_valid 200 301 302 1d;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_cache_key http://$host$request_uri;
全局定義一個緩存空間,配置文件名為,fastcgi_cache.conf,然后在vhost配置里面加上:
include fastcgi.conf;
大概解釋下各個參數的含義:
fastcgi_temp_path:生成fastcgi_cache臨時文件目錄,fastcgi_cache_path:fastcgi_cache緩存目錄,可以設置目錄哈希層級,比如2:2會生成256*256個字目錄,keys_zone是這個緩存空間的名字,cache是用多少內存(這樣熱門的內容nginx直接放內存,提高訪問速度),inactive表示默認失效時間,max_size表示最多用多少硬盤空間,需要注意的是fastcgi_cache緩存是先寫在fastcgi_temp_path再移到fastcgi_cache_path,所以這兩個目錄最好在同一個分區,從0.8.9之后可以在不同的分區,不過還是建議放同一分區。
fastcgi_cache_valid:定義哪些http頭要緩存,fastcgi_cache_use_stale:定義哪些情況下用過期緩存
fastcgi_cache_key:定義fastcgi_cache的key,示例中就以請求的URI作為緩存的key,Nginx會取這個key的md5作為緩存文件,如果設置了緩存哈希目錄,Nginx會從后往前取相應的位數做為目錄。
fastcgi_cache:用哪個緩存空間
這樣就可以了,基本上可以work,但還沒完,如何手動清除緩存?有個Nginx的第三方擴展可幫你做到:https://github.com/FRiCKLE/ngx_cache_purge/,如果對大多數第三方擴展無愛,寫個清除的腳本也非常簡單,以PHP為例:
function purgeCache()
{
$url = $this->post('url');
if (empty($url) || !Cola_Com_Validate::url($url)) {
exit('請輸入正確的URL。');
}
$md5 = md5($url);
$cacheFile = $this->_cacheRoot . '/' . substr($md5, -2, 2) . '/' . substr($md5, -4, 2) . '/' . $md5;
if (!file_exists($cacheFile)) {
exit('緩存不存在。');
}
if (@unlink($cacheFile)) {
echo '清除緩存成功。';
} else {
echo '清除緩存失敗。';
}
}
核心是第11行,直接找到緩存文件,然后刪掉就可以,這個腳本有個副作用,手動清除之后,緩存失效,但Nginx后面還會自己清除一遍,然后報個unlink失敗的日志,不過無關緊要了。
淡定,文章還沒完,要不就成標題黨了,Nginx fastcgi_cache緩存很不錯,但我只想在某些頁面用fastcgi_cache,很簡單,有兩種方法,一是在location中定義fastcgi_cache,這樣只有滿足一定規則的url才會用上cache,其他的就不會了;另外一種方法是在你不需要緩存的頁面上,輸出禁止緩存的頭信息,用ColaPHP的話,直接$this->response->disableBrowserCache(); 具體代碼:
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
這樣就告訴Nginx,這個頁面不需要緩存。
好吧,要淡定不要D疼,還有最后一個問題,如果頁面中只有一小部分內容不可以緩存,可以用Nginx fastcgi_cache嗎?比如某個內容頁,大部分內容可以緩存,但希望把用戶的登錄信息更新上去。答案是肯定的,可以直接輸出用戶未登錄的頁面樣式,等頁面加載完畢之后,通過ajax異步更新用戶信息:
initUser();
})
碼完收工。