【nginx】關於fastcgi_cache,nginxfastcgi_cache
一、簡介
Nginx版本從0.7.48開始,支援了類似Squid的緩衝功能。這個緩衝是把URL及相關組合當做Key,用Md5演算法對Key進行雜湊,得到硬碟上對應的雜湊目錄路徑,從而將緩衝內容儲存在該目錄內。
Nginx Web 快取服務只能為指定URL或狀態代碼設定到期時間,不支援類似Squid的PURGE指令手動清除緩衝;但是我們可以通過Nginx的模組ngx_cache_purge清除指定URL的緩衝。
- proxy_cache:緩衝後端伺服器的內容,可能是任何內容,包括靜態和動態,減少了nginx與後端通訊的次數,節省了傳輸時間和後端寬頻
- fastcgi_cache:緩衝fastcgi產生的內容,很多情況是php產生的動態內容,少了nginx與php的通訊的次數,更減輕了php和資料庫(mysql)的壓力,這比用memcached之類的緩衝要輕鬆得多
圖片來自網路
二、配置
nginx.conf
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;fastcgi_cache_key "$scheme$request_method$host$request_uri";fastcgi_cache_use_stale error timeout invalid_header http_500;fastcgi_ignore_headers Cache-Control Expires Set-Cookie;fastcgi_temp_path /tmp/nginx/fcgi/temp;
vhost配置
server {server_name example.com www.example.com;access_log /var/log/nginx/example.com.access.log;error_log /var/log/nginx/example.com.error.log;root /var/www/example.com/htdocs;index index.php;set $skip_cache 0;# POST requests and urls with a query string should always go to PHPif ($request_method = POST) {set $skip_cache 1;} if ($query_string != "") {set $skip_cache 1;} # Don't cache uris containing the following segmentsif ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {set $skip_cache 1;} # Don't use the cache for logged in users or recent commentersif ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {set $skip_cache 1;}location / {try_files $uri $uri/ /index.php?$args;} location ~ \.php($|/) {try_files $uri =404; include fastcgi_params;fastcgi_split_path_info ^(.+\.php)(/.+)$;fastcgi_param PATH_INFO $fastcgi_path_info;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_pass unix:/dev/shm/php-socket;fastcgi_cache_bypass $skip_cache;fastcgi_no_cache $skip_cache;fastcgi_cache WORDPRESS;include fcgi_cache_params;}location ~ /purge(/.*) { fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";}location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {access_log off;log_not_found off; expires max;}location = /robots.txt { access_log off; log_not_found off; }location ~ /\. { deny all; access_log off; log_not_found off; }}
fcgi_cache_params配置
#include fcgi_cache_params;#fastcgi_cache_valid 200 302 1s;### fcgi-cachefastcgi_cache fcgi;fastcgi_cache_valid 200 302 1s;fastcgi_cache_valid 404 500 502 503 504 0s;fastcgi_cache_valid any 1m;fastcgi_cache_min_uses 1;fastcgi_cache_use_stale error timeout invalid_header http_500 http_503 updating;fastcgi_ignore_headers Cache-Control Expires Set-Cookie;#add_header X-Cache "$upstream_cache_status - $upstream_response_time";fastcgi_cache_key "$scheme$request_method$host$request_uri"
大概解釋下各個參數的含義:
fastcgi_cache 該指令用於設定哪個緩衝區將被使用,zone_name的值為fastcgi_cache_path指令建立的緩衝名稱
fastcgi_cache_path 範圍:http
fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
該指令用於設定快取檔案的存放路徑,樣本如下:fastcgi_cache_path /data/nginx/cache levels=1:2 keys_zone=cache_one:100M inactive=1d max_size=10g;
a、levels:指定了該緩衝空間有兩層hash目錄,設定緩衝目錄層數,levels=1:2,表示建立兩層目錄緩衝,最多建立三層。第一層目錄名取fastcgi_cache_key md5的最後一個字元,第二層目錄名取倒數2-3字元,如:fastcgi_cache_key md5為b7f54b2df7773722d382f4809d65029c,則:
levels=1:2為/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029clevels=1:2:3為/data/nginx/cache/c/29/650/b7f54b2df7773722d382f4809d65029c
b、keys_zone為這個緩衝區起名為zone_name,500m指代緩衝空間為500MB;
c、inactive=1d 代表如果快取檔案一天內沒有被訪問,則刪除;
d、max_size=30g代表硬碟緩衝最大為30G;
設定緩衝多個磁碟
fastcgi_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m max_size=10g inactive=60m use_temp_path=off;fastcgi_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m max_size=10g inactive=60m use_temp_path=off;split_clients $request_uri $my_cache { 50% "my_cache_hdd1"; 50% "my_cache_hdd2";}server { ... location / { fastcgi_cache $my_cache; }}
將快取檔案放入記憶體中
編輯/etc/fstab 或者 放入 /dev/shm
tmpfs /etc/nginx/cache tmpfs defaults,size=100M 0 0mount -adf -ah | grep tmpfs
需要注意的是fastcgi_cache緩衝是先寫在fastcgi_temp_path再移到fastcgi_cache_path,所以這兩個目錄最好在同一個分區,從0.8.9之後可以在不同的分區,不過還是建議放同一分區
fastcgi_cache_methods 該指令用於設定緩衝哪些HTTP方法,預設緩衝HTTP GET/HEAD方法。
fastcgi_cache_min_uses URL經過多少次請求將被緩衝
fastcgi_cache_valid reply_code [reply_code ... ] time
該指令用於對不同返回狀態代碼的URL設定不同的緩衝時間,例如:
fastcgi_cache_valid 200 302 10m;fastcgi_cache_valid 404 1m;
設定202 302狀態URL緩衝10分鐘,404狀態的URL緩衝1分鐘。
注意:如果不指定狀態代碼,直接指定緩衝時間,則只有200,301,302狀態代碼會進行緩衝。
fastcgi_cache_valid 5m;
any 可以指定緩衝任何響應碼
fastcgi_cache_valid 200 302 10m;fastcgi_cache_valid 301 1h;fastcgi_cache_valid any 1m;
緩衝的參數也可以在回應標頭直接設定。這些的優先順序高於緩衝時間設定使用該指令
- The “X-Accel-Expires” header field sets caching time of a response in seconds. The zero value disables caching for a response. If the value starts with the
@ prefix, it sets an absolute time in seconds since Epoch, up to which the response may be cached.
- If the header does not include the “X-Accel-Expires” field, parameters of caching may be set in the header fields “Expires” or “Cache-Control”.
- If the header includes the “Set-Cookie” field, such a response will not be cached.
- If the header includes the “Vary” field with the special value “
*”, such a response will not be cached (1.7.7). If the header includes the “Vary” field with another value, such a response will be cached taking into account the corresponding request header fields (1.7.7).
fastcgi_cache_key
該指令用來設定Web緩衝的Key值,Nginx根據Key值MD5緩衝。一般根據$host(網域名稱),$request_uri(請求的路徑)等變數組合成fastcgi_cache_key。
例如:fastcgi_cache_key "$scheme$request_method$host$request_uri";
定義fastcgi_cache的key,樣本中就以請求的URI作為緩衝的key,Nginx會取這個key的md5作為快取檔案,如果設定了緩衝雜湊目錄,Nginx會從後往前取相應的位元做為目錄。
注意一定要加上$request_method作為cache key,否則如果HEAD類型的先請求會導致後面的GET請求返回為空白
fastcgi_temp_path path [level1 [level2 [level3]]]; 預設為 fastcgi_temp;
該指令用來設定fastcgi_cache臨時檔案目錄
fastcgi_temp_path /spool/nginx/fastcgi_temp 1 2;
a temporary file might look like this:
/spool/nginx/fastcgi_temp/7/45/00000123457
fastcgi_cache_use_stale : fastcgi_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_503 | http_403 | http_404 | off ...;
定義哪些情況下用到期緩衝
x-cache頭,用於調試
$upstream_response_time為到期時間
$upstream_cache_status 變數表示此請求響應來自cache的狀態,幾種狀態分別為:
- MISS – The response was not found in the cache and so was fetched from an origin server. The response might then have been cached.
- BYPASS – The response was fetched from the origin server instead of served from the cache because the request matched a proxy_cache_bypass directive (see Can I Punch a Hole Through My Cache? below.) The response might then have been cached.
- EXPIRED – The entry in the cache has expired. The response contains fresh content from the origin server.
- STALE – The content is stale because the origin server is not responding correctly, and proxy_cache_use_stale was configured.
- UPDATING – The content is stale because the entry is currently being updated in response to a previous request, and proxy_cache_use_stale updating is configured.
- REVALIDATED – The proxy_cache_revalidate directive was enabled and NGINX verified that the current cached content was still valid (If-Modified-Since or If-None-Match).
- HIT – The response contains valid, fresh content direct from the cache.
有一些情況會影響到cache的命中 這裡需要特別注意
- Nginx fastcgi_cache在緩衝後端fastcgi響應時,當響應裡包含“set-cookie”時,不緩衝;
- 當回應標頭包含Expires時,如果到期時間大於當前伺服器時間,則nginx_cache會緩衝該響應,否則,則不緩衝;
- 當回應標頭包含Cache-Control時,如果Cache-Control參數值為no-cache、no-store、private中任意一個時,則不緩衝,如果Cache-Control參數值為max-age時,會被緩衝,且nginx設定的cache的到期時間,就是系統目前時間 + mag-age的值。
header("Expires: ".gmdate("D, d M Y H:i:s", time()+10000).' GMT');header("Expires: ".gmdate("D, d M Y H:i:s", time()-99999).' GMT');header("X-Accel-Expires:5"); // 5sheader("Cache-Control: no-cache"); //no cacheheader("Cache-Control: no-store"); //no cacheheader("Cache-Control: private"); //no cacheheader("Cache-Control: max-age=10"); //cache 10ssetcookie('hello',"testaaaa"); //no cache
注意session使用的時候有坑,可以用下面來設定
session_cache_limiter("none");session_start();echo date("Y-m-d H:i:s",time());可以看一下PHP原始碼中的頭資訊 Expires等
//ext/session/session.c line:1190 左右// ...CACHE_LIMITER_FUNC(private) /* {{{ */{ ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT"); CACHE_LIMITER(private_no_expire)(TSRMLS_C);}/* }}} *///再到這裡3 或者上面幾個 ##預設是nocacheCACHE_LIMITER_FUNC(nocache) /* {{{ */{ ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT"); /* For HTTP/1.1 conforming clients and the rest (MSIE 5) */ ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); /* For HTTP/1.0 conforming clients */ ADD_HEADER("Pragma: no-cache");}/* }}} *///這裡2static php_session_cache_limiter_t php_session_cache_limiters[] = { CACHE_LIMITER_ENTRY(public) CACHE_LIMITER_ENTRY(private) CACHE_LIMITER_ENTRY(private_no_expire) CACHE_LIMITER_ENTRY(nocache) {0}}; static int php_session_cache_limiter(TSRMLS_D) /* {{{ */{ php_session_cache_limiter_t *lim; if (PS(cache_limiter)[0] == '\0') return 0; if (SG(headers_sent)) { const char *output_start_filename = php_output_get_start_filename(TSRMLS_C); int output_start_lineno = php_output_get_start_lineno(TSRMLS_C); if (output_start_filename) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cache limiter - headers already sent (output started at %s:%d)", output_start_filename, output_start_lineno); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cache limiter - headers already sent"); } return -2; } for (lim = php_session_cache_limiters; lim->name; lim++) { if (!strcasecmp(lim->name, PS(cache_limiter))) { lim->func(TSRMLS_C); //這裡1 return 0; } } return -1;}三、清除緩衝
NGINX只在商業版中支援proxy_cache_purge指令清除緩衝,開源的ngx_cache_purge模組只支援單一key的緩衝清除。為了實現按目錄清除緩衝只能自己開發。
NGINX作為Cache伺服器時將資源內容以檔案形式進行緩衝,緩衝元資訊儲存於共用記憶體中,組織成一棵紅/黑樹狀結構。紅/黑樹狀結構中的每個節點代表一個Cache元資訊。NGINX將Cache Key的HASH值作為紅/黑樹狀結構節點的KEY。內容快取檔案以該HASH值作為檔案名稱儲存在磁碟上。
NGINX的處理流程簡化描述是這樣的:當請求到達時,根據Cache Key的HASH值在紅/黑樹狀結構中進行尋找。如果找到,並查看相關資訊,如果Cache可用,返回相應的Cache檔案。否則,則回源抓取。
因為元資訊是以Cache Key的HASH值作為Key儲存的,因而紅/黑樹狀結構中並不能保留Cache Key中有層級關係. 如”/uri/foo”和”/uri/bar”在元資訊紅/黑樹狀結構中完全沒有關係。要實現按照目錄清除緩衝,需要將Cache Key中層次關係儲存起來。
可以這樣做,在共用記憶體中建立一棵分類樹來儲存層級關係。將Cache Key類比於檔案系統中的路徑, 每級路徑儲存為樹中的一個節點。當需要清除某一目錄下的所有緩衝時,將該節點子樹的中的所有緩衝清除即可。
安裝Purge模組
Purge模組被用來清除緩衝
wget http://labs.frickle.com/files/ngx_cache_purge-1.2.tar.gztar -zxvf ngx_cache_purge-1.2.tar.gz
編譯
./configure \…… \--with-http_geoip_module \--add-module=/usr/local/ngx_cache_purge-1.2
四、需要注意的一些問題
設定了之後重啟nginx就可以生效了,這個時候再訪問php的頁面的話,就會被緩衝了,可以查看/var/logs/nginx/fastcgi_cache_dir這個目錄下面是有快取檔案的。最後再說明一點,如果更改了緩衝目錄的路徑,一定要把緩衝的名稱也改掉,後端調用的名稱也同步改掉,如果只改掉了緩衝目錄,不改緩衝名稱的話,緩衝的時候還是會緩衝到之前的路徑下面去,但是調用的時候調用的是新的路徑,這個時候就會出現找不到的情況
參考文章
http://www.nginxtips.com/configure-nginx-fastcgi-cache/
http://www.haidx.com/fastcgi-cache-details.html
http://www.just4coding.com/blog/2014/11/01/nginx-purge-directory/
http://weizhifeng.net/nginx-proxy-cache.html
https://www.nginx.com/blog/nginx-caching-guide/#gs.6PdbraI
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache
https://www.cnxct.com/several-reminder-in-nginx-fastcgi_cache-and-php-session_cache_limiter/
https://rtcamp.com/wordpress-nginx/tutorials/single-site/fastcgi-cache-with-purging/
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache