
最近正將varnish上的cache policy遷移到nginx proxy cache上,并為后續(xù)使用memorycached緩存做好準(zhǔn)備,下文對(duì)最近的工作進(jìn)行下梳理和總結(jié),歡迎糾錯(cuò)和探討:
1. 基礎(chǔ)
* 緩存概念

悶著頭皮做了好幾天,將最初的配置模版寫(xiě)出來(lái)了,但是忽略了最重要的一點(diǎn):Basic Principles,所以讓我老大批評(píng)了一頓,并改了不少東西,痛定思痛,開(kāi)始看原理:上圖是用戶(hù)訪問(wèn)website流程圖(nginx為proxy)
當(dāng)?shù)谝粋€(gè)用戶(hù)(藍(lán))訪問(wèn)網(wǎng)站,他的請(qǐng)求首先會(huì)到NGINX PROXY SERVER,隨后NGNIX發(fā)往后端服務(wù)器(灰),后端會(huì)將請(qǐng)求的響應(yīng)首先發(fā)往NGINX,由其返回給用戶(hù)(藍(lán)色),如果這個(gè)響應(yīng)是可以緩存的,則NGINX會(huì)保留一份響應(yīng)的副本,當(dāng)其他用戶(hù)(橙色)發(fā)起相同的request請(qǐng)求時(shí),NGINX會(huì)根據(jù)request請(qǐng)求的內(nèi)容是否存在于緩存中,來(lái)直接返回給用戶(hù),不經(jīng)過(guò)后端。這個(gè)場(chǎng)景同樣適用于瀏覽器,CDN,用于緩存靜態(tài)資源。
* HTTP緩存機(jī)制
后端服務(wù)器會(huì)通過(guò)響應(yīng)包頭來(lái)定義緩存特性:

當(dāng)然,緩存服務(wù)器可以通過(guò)設(shè)置一些參數(shù)來(lái)忽略或者重寫(xiě)后端服務(wù)器的緩存特性,但后端服務(wù)器的緩存特性也是極其重要的。
.Expires: 最原始的配置策略,即設(shè)置過(guò)期時(shí)間,但使用效率低下,目前絕大部分已經(jīng)被Cache-Control(有興趣的可以去看下http1.0和http1.1);
.Cache-Control:定義緩存資源屬性是private或者是public,并且設(shè)置緩存多久后過(guò)期,本例中,屬性為public,60秒過(guò)期;
.X-Accel-Expires: 只有nginx能識(shí)別的緩存特性header,優(yōu)先級(jí)大于上面兩個(gè)header,可以設(shè)置此header,在nginx側(cè)來(lái)重新定義緩存特性;
.Etag和Last-Modified是捆綁生成的: 有些場(chǎng)景下,你希望client端的瀏覽器長(zhǎng)時(shí)間緩存,而緩存服務(wù)器只短時(shí)間緩存文件,以至于當(dāng)后端服務(wù)器更新后,緩存服務(wù)器會(huì)及時(shí)同步,我們就可以使用最后兩個(gè)header,Last-Modified表示最后修改時(shí)間,并聲明一個(gè)ETag(哈希值),做為緩存內(nèi)容的標(biāo)簽,具有唯一性;客戶(hù)端訪問(wèn)請(qǐng)求帶有If?Modified?Since或者If?None?Match header,并申明自己的客戶(hù)端帶有靜態(tài)緩存文件,以及文件修改日期和ETag值,如果服務(wù)器端的版本和Etag值與客戶(hù)端一致,則服務(wù)端會(huì)直接返回304 not modified,這個(gè)驗(yàn)證流程是非??斓?,并且節(jié)省網(wǎng)絡(luò)帶寬;
.如果Cache-Control設(shè)置為public,則客戶(hù)端不會(huì)去驗(yàn)證資源的有效性,將會(huì)一直使用直到過(guò)期,同時(shí)public也代表資源可以被緩存在web proxy中;
.如果Cache-Control包含must-revalidate,則客戶(hù)端每一次訪問(wèn)請(qǐng)求資源都會(huì)去驗(yàn)證緩存是否有更新;
* NGINX都會(huì)緩存哪些資源
2. 最佳實(shí)踐
首先看下nginx proxy cache最基本的配置:
proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
???? set $upstream http://ip:port
???? ???? location / {
???? ???????? ???? proxy_cache my_cache;
???? ???????? ???? proxy_pass $upstream; }
???? ????}
配置項(xiàng)說(shuō)明:
/path/to/cache : 本地路徑,緩存文件存放地址;levels : 默認(rèn)所有緩存文件都放在同一個(gè)/path/to/cache下,從而影響緩存的性能,大部分場(chǎng)景推薦使用2級(jí)目錄來(lái)存儲(chǔ)緩存文件;key_zone : 在共享內(nèi)存中設(shè)置一塊存儲(chǔ)區(qū)域來(lái)存放緩存的key和metadata(類(lèi)似使用次數(shù)),這樣nginx可以快速判斷一個(gè)request是否命中或者未命中緩存,1m可以存儲(chǔ)8000個(gè)key,10m可以存儲(chǔ)80000個(gè)key;max_size : 最大cache空間,如果不指定,會(huì)使用掉所有disk space,當(dāng)達(dá)到配額后,會(huì)刪除最少使用的cache文件;inactive : 未被訪問(wèn)文件在緩存中保留時(shí)間,本配置中如果60分鐘未被訪問(wèn)則不論狀態(tài)是否為expired,緩存控制程序會(huì)刪掉文件,默認(rèn)為10分鐘;“需要注意的是,inactive和expired配置項(xiàng)的含義是不同的,expired只是緩存過(guò)期,但不會(huì)被刪除,inactive是刪除指定時(shí)間內(nèi)未被訪問(wèn)的緩存文件”;use_temp_path : 如果為off,則nginx會(huì)將緩存文件直接寫(xiě)入指定的cache文件中,而不是使用temp_path存儲(chǔ),official建議為off,避免文件在不同文件系統(tǒng)中不必要的拷貝;proxy_cache : 啟用proxy cache,指定key_zone;
附:緩存和代理中常用的配置項(xiàng)
上文講述了如何配置最基礎(chǔ)的proxy cache,接下來(lái),會(huì)對(duì)常用的高級(jí)配置項(xiàng)進(jìn)行梳理。
- proxy_no_cache string;
Default: —
Context: http , server , location
config example:
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
proxy_no_cache $http_pragma $http_authorization;
$cookie_nocache $arg_nocache...皆為變量,可以根據(jù)你訪問(wèn)的匹配策略來(lái)設(shè)置,其值只有2類(lèi),0和非0;
訪問(wèn)匹配策略例如:
if ($request_uri ~ ^/(login|register|password\/reset)/) { set $cookie_nocache 1; }
如果在此鏈?zhǔn)脚渲弥校灰幸粋€(gè)值不為0,則不會(huì)cache;例如:proxy_no_cache $cookie_nocache(0) $arg_nocache(1) $arg_comment(0),不會(huì)被cache。`
注:一般會(huì)配合proxy_cache_bypass共同使用;
- proxy_cache_bypass string;
Default: —
Context: http , server , location
config example:
proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;
定義在哪些情況下不從cache讀取,直接從backend獲取資源;配置方式同proxy_no_cache。
- proxy_cache_key string;
Default: proxy_cache_key $scheme$proxy_host$request_uri;
Context: http, server, location
自定義cache key,例如:
proxy_cache_key "$host$request_uri $cookie_user";
默認(rèn)值為:
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
- proxy_cache_methods GET| HEAD|POST...;
Default: proxy_cache_methods GET HEAD;
Context: http, server, location
指定客戶(hù)端那些方法被緩存,默認(rèn)為GET|HEAD。
- proxy_cache_purge string ...;
Default: —
Context: http, server, location
config example:
proxy_cache_path /data/nginx/cache keys_zone=cache_zone:10m;
map $request_method $purge_method {
???? PURGE 1;
???? default 0;
}
server {
???? ...
???? location / {
???? ???? proxy_pass http://backend;
???? ???? proxy_cache cache_zone;
???? ???? proxy_cache_key $uri;
???? ???? proxy_cache_purge $purge_method;
???? }
}
定義緩存清除場(chǎng)景,同proxy_no_cache,proxy_cache_bypass鏈?zhǔn)脚渲梅绞?,只要又一個(gè)不為0,則清除對(duì)應(yīng)的cache key則會(huì)被清除,并返回204 response。注意,這里是刪除內(nèi)存中的cache key,而不是disk上的cache文件?。?!disk的cache文件是由inactive控制;
當(dāng)purege request的cache key以通配符*結(jié)束時(shí),所有匹配到通配符的cache入口的cachekey都會(huì)被刪除。
- proxy_cache_valid *[code...] time *;
Default: —
Context: http, server, location
設(shè)置不同相應(yīng)碼的緩存時(shí)間,當(dāng)不指定響應(yīng)碼的時(shí)候,例如
proxy_cache_valid 5m;
只對(duì)響應(yīng)碼為200,301,302的訪問(wèn)請(qǐng)求資源設(shè)置緩存時(shí)間,此外可以個(gè)性化定制,例如:
proxy_cache_valid 200 302 10m; proxy_cache_valid 301 1h; proxy_cache_valid 404 1m; proxy_cache_valid any 1m;
此外,還可以在相應(yīng)header里設(shè)置優(yōu)先級(jí)更高的緩存有效時(shí)間:
- “X-Accel-Expires”,設(shè)置響應(yīng)的緩存過(guò)期時(shí)間,以秒為單位;0為不緩存;
- 如果沒(méi)有設(shè)置“X-Accel-Expires” header,則關(guān)于緩存的配置策略可能會(huì)在“Expires”或者“Cache-Control” header中;
- 如果header含有“Set-Cookie”,則響應(yīng)不會(huì)被緩存,類(lèi)似的配置可以在“proxy_ignore_header”中可見(jiàn);
- header包含“Vary”并且設(shè)置為“*”,則請(qǐng)求不會(huì)被緩存,如果“Vary”有具體的值,則對(duì)應(yīng)的請(qǐng)求會(huì)被緩存;
- proxy_ignore_headers field;
Default: —
Context: http, server, location
不緩存包含在field的響應(yīng)header,可以設(shè)置的值有:“X-Accel-Redirect”, “X-Accel-Expires”, “X-Accel-Limit-Rate”,“X-Accel-Buffering”, “X-Accel-Charset”, “Expires”, “Cache-Control”, “Set-Cookie” (0.8.44), and “Vary”。
如果上述的header field沒(méi)有設(shè)置為忽略,則header filed中有“X-Accel-Expires”, “Expires”, “Cache-Control”, “Set-Cookie”, and “Vary”的話(huà),響應(yīng)會(huì)被緩存。
- proxy_pass_headers field;
- proxy_hide_headers field;
Default: —
Context: http, server, location
參考: 1.http://czerasz.com/2015/03/30/nginx-caching-tutorial/ 2.https://www.nginx.com/blog/nginx-caching-guide/ 3.https://www.nginx.com/blog/nginx-high-performance-caching/ 4.http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers 5.http://www.slideshare.net/Nginx/nginx-highperformance-caching 6.https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching 7.http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers 8.https://forum.nginx.org/read.php?2,265703,265704#msg-265704