1、緩存區
緩存內容并定義緩存的存儲位置。
使用 proxy_cache_path 指令定義共享內存緩存區和內容的位置:
proxy_cache_path /var/nginx/cachekeys_zone=CACHE:60m levels=1:2inactive=3h max_size=20g;
proxy_cache CACHE;
上述緩存定義示例在文件系統 /var/nginx/cache 中為緩存響應創建了一個目錄,以及一個名為 CACHE、大小為 60M 的共享內存空間。此示例設置了目錄結構級別,定義了如果緩存響應在 3 小時內未被請求就被釋放,同時定義了最大緩存大小為 20GB。proxy_cache 指令通知特定上下文使用緩存區。proxy_cache_path 在 http 上下文中有效,proxy_cache 指令在 http、server 和 location 上下文中有效。
詳解
要在 NGINX 中配置緩存,就必須聲明要使用的路徑和區域。您可以使用 proxy_cache_path 指令創建 NGINX 中的緩存區。proxy_cache_path 指定了存儲緩存信息的位置,以及存儲活動鍵和響應元數據的共享內存空間。該指令的可選參數對維護和訪問緩存的方式提供了更多控制。levels 參數定義了文件結構的創建方式。該值用冒號分隔,聲明了子目錄名稱的長度,最多支持三個級別。NGINX 緩存以緩存鍵(一個哈希值)為基礎,它將結果存儲在提供的文件結構中,使用緩存鍵作為文件路徑并根據levels 值分解目錄。inactive 參數能夠控制緩存項在最后一次使用后駐留的時間長度。您也可以使用 max_size 參數配置緩存的大小。其他參數與緩存加載進程有關,這個進
程可以將緩存鍵從磁盤的緩存文件加載到共享內存
2、緩存鎖定
您不希望 NGINX 將當前正在寫入緩存的請求代理到上游(upstream)服務器。
使用 proxy_cache_lock 指令確保一次只能將一個請求寫入緩存,隨后的請求將等待響應被寫入:
proxy_cache_lock on;
proxy_cache_lock_age 10s;
proxy_cache_lock_timeout 3s;
詳解
proxy_cache_lock 指令指示 NGINX 保存當前正在填充的請求,這些請求最終將成為被緩存的元素。根據 proxy_cache_lock_age 指令的定義,代理請求填充緩存的時間是有限制的,默認為 5 秒,此后才允許另一個請求填充元素。NGINX 還允許將已經等待指定時間(同樣默認為 5 秒)的請求傳遞到代理服務器,該請求不會嘗試通過使用 proxy_cache_lock_timeout 指令來填充緩存。您可以將 proxy_cache_lock_age 理解成“你花的時間太長了,我來為你填充緩存”,將 proxy_cache_lock_timeout 理解成“你讓我等的時間太長了,你先慢慢填充,我去干點別的”。
3、緩存哈希鍵
控制內容的緩存和檢索方式。
使用 proxy_cache_key 指令和變量定義緩存的命中或未命中:
proxy_cache_key "$host$request_uri $cookie_user";
上述緩存哈希鍵將根據被請求的主機和 URI、定義用戶的 cookie 指示 NGINX 緩存頁面。這樣您就可以緩存動態頁面,而且不用提供為其他用戶生成的內容。
詳解
proxy_cache_key 的默認配置是“ s c h e m e scheme schemeproxy_host$request_uri”,該配置適用于大多數用例。使用的變量包括 scheme、HTTP 或 HTTPS、proxy_host(發送請求)以及請求 URI。總之,這反映了 NGINX 將請求代理到哪個 URL。您可能會發現,還有許多其他因素定義了每個應用的唯一請求,比如請求參數、請求頭、會話標識符等等,您希望為這些因素創建自己的哈希鍵。
NGINX 提供了這些變量的列表
選擇一個好的哈希鍵非常重要,其中離不開對應用的了解。為靜態內容選擇緩存鍵通常非常簡單,只需使用主機名和 URI 便可。但如果是為相當動態的內容(例如儀表盤應用的頁面)選擇緩存鍵,就要求對用戶與應用的交互方式以及用戶體驗之間的差異程度有著更深刻的認識。出于安全考慮,您可能不希望在沒有完全了解上下文的情況下就將用戶的緩存數據展示給其他用戶。proxy_cache_key 指令將字符串配置為緩存鍵的哈希值,該指令可以在 http、server 和 location 代碼塊中進行設置,從而靈活控制請求的緩存方式。
4、繞過緩存
繞過緩存。
使用具有非空或非零值的 proxy_cache_bypass 指令。動態執行此操作的一種方法是,在您不希望進行緩存的 location 代碼塊內,使用一組字符串不能為空或為 0 的變量:
proxy_cache_bypass $http_cache_bypass;
該配置指示 NGINX,如果名為 cache_bypass 的 HTTP 請求頭的值不是 0,則繞過緩存。本例使用請求頭作為變量來確定是否應該繞過緩存 —— 客戶端需要專門為其請求設置此請求頭。
詳解
我們有很多使用場景都不要求緩存請求。為此,NGINX 提供了 proxy_cache_bypass 指令。這樣,當值設置為非空或非零時,請求將被發送到上游(upstream)服務器,而不是從緩存中拉取。繞過緩存的不同需求和場景將由您的應用的用例來決定。繞過緩存可以簡單到只需使用請求頭或響應頭就能搞定,也會復雜到協同配合多個 map 代碼塊來解決。
繞過緩存的原因有很多,比如為了故障排除或調試。如果您總是拉取緩存的頁面,或者您的緩存鍵只是針對一個用戶標識符的,那么復盤問題可能會很難。因此,具備繞過緩存的能力十分重要。繞過緩存的方法有很多,包括但不限于設置特定的 cookie、請求頭或請求參數時等。您還可以通過設置 proxy_cache off;,徹底關閉給定上下文(例如 location 代碼塊)的緩存功能。
5、緩存性能
通過在客戶端緩存內容來提高性能。
使用客戶端的 cache-control HTTP 請求頭:
location ~* \.(css|js)$ { expires 1y;add_header Cache-Control "public";
}
這個 location 代碼塊指定客戶端可以緩存 CSS 和 JavaScript 文件的內容。expires 指令指示客戶端將緩存資源的有效期設置為一年。add_header 指令將 HTTP 響應頭Cache-Control 添加到響應中,值為 public,允許沿途的所有緩存服務器緩存資源。如果將值設置為 private,則只允許客戶端緩存資源。
詳解
緩存性能有許多影響因素,其中磁盤速度最為重要。NGINX 配置中有很多指令可以幫助提升緩存性能。其中一種方法是設置 HTTP 響應頭,讓客戶端只緩存響應但是不向NGINX 發送請求,這樣只需讀取緩存便可。
6、NGINX Plus 之緩存清除
使緩存中的對象變得無效。
使用 proxy_cache_purge 指令(NGINX Plus 的清除功能)以及非空或零值變量:
map $request_method $purge_method { PURGE 1;default 0;
}
server {# ...location / {# ...proxy_cache_purge $purge_method;}
}
在此示例中,如果使用 PURGE 方法請求特定對象,那么它的緩存將被清除。以下是使用 curl 清除名為 main.js 的文件緩存的示例:
$ curl -XPURGE localhost/main.js
詳解
處理靜態文件的一種常見方法是將文件的哈希放在文件名中。當您推出新的代碼和內容時,這可以確保您的 CDN 將其識別為新文件(因為 URI 已更改)。但是,對設置了不適合此模型的緩存鍵的動態內容來說,這種方法并不好用。在每種緩存場景中,您都必須有一種對應的清除緩存的方法。NGINX Plus 的處理方法很簡單,只要將 proxy_cache_purge 指令的值設置為非零或非空,與請求匹配的緩存項就被會清除掉。此外還有一種簡便方法,那就是為 PURGE 映射請求方法。但是您可能需要配合使用 geo_ip 模塊或簡單的身份驗證方法,以確保不是任何人都能清除您寶貴的緩存項。NGINX 還允許使用 * 來清除與常見 URI 前綴相匹配的緩存項。要使用通配符,您需要使用
purger=on 參數配置 proxy_cache_path 指令。
7、緩存切片
需要通過將文件分段來提高緩存效率。
使用 NGINX slice 指令及其嵌入式變量將緩存結果分段:
proxy_cache_path /tmp/mycache keys_zone=mycache:10m;
server {# ...proxy_cache mycache;slice 1m;proxy_cache_key $host$uri$is_args$args$slice_range;proxy_set_header Range $slice_range; proxy_http_version 1.1;proxy_cache_valid 200 206 1h;location / {proxy_pass http://origin:80;}
}
詳解
此配置為服務器定義并啟用了一個緩存區。slice 指令指示 NGINX 將響應分成 1MB 的文件段。緩存文件根據 proxy_cache_key 指令進行存儲。請注意,該指令使用了一個名為 slice_range 的嵌入式變量。向源端發送請求時也使用了同一變量作為請求頭,并且該請求的 HTTP 版本已升級到 HTTP/1.1,因為 1.0 不支持字節范圍的請求。200 或206 響應碼的緩存有效期設為 1 個小時,然后定義位置和源端。
Cache Slice 模塊是為了交付 HTML5 視頻開發的,它使用字節范圍的請求將偽流內容傳輸到瀏覽器。默認情況下,NGINX 能夠從緩存中提供字節范圍的請求。如果對未緩存的內容發出了一個字節范圍的請求,NGINX 將向源端請求整個文件。當您使用Cache Slice 模塊時,NGINX 僅向源端請求必要的文件段。如果請求范圍大于切片大小(包括整個文件),就會觸發對每個所需文件段的子請求,并對這些文件段進行緩存處理。當所有文件段都被緩存后,系統將組合響應并將它們發送給客戶端,這使得NGINX 能夠更有效地緩存并提供請求的范圍內的內容。
Cache Slice 模塊只能用于不會進行更改的大文件。NGINX 每接收一個來自源端的文件段,就驗證一次 ETag。如果源端的 ETag 發生了變化,那么由于緩存不再有效,NGINX 就會中止這個段的緩存填充。如果內容確實發生了變化,文件也變小了,或者如果源端可以處理緩存填充過程中的負載峰值,那么最好使用下面“其他參考資料”所列博客中描述的 Cache Lock 模塊。默認情況下不創建該模塊,您需要在構建 NGINX 時使用 --with-http_slice_module 配置來啟用。
參考資料
“使用 NGINX 和 NGINX Plus 智能高效地進行字節范圍的緩存”