技術積澱----NGINX緩存

整潔的代碼,合理的架構是一個性能卓越的應用不可或缺的優點。同時在很多案例中,開發者投入一些精力在一些最基本的技術上,也可以帶來非常大的性能提升。這些基礎的技術包括就包括緩存技術。本文主要介紹下如何利用NGINX緩存提升系統性能。

nginx常常被當做反向代理、負載均衡器。同時nginx還具備強大的緩存特性,接下來我們將介紹如何配置nginx緩存。


如何配置最基礎的緩存。

使用最基本的緩存功能,只需要兩個NGINX指令:proxy_cache_path 和 proxy_cache。 proxy_cache_path 指令設置緩存路徑和一些緩存配置,proxy_cache 指令用來使用NGINX緩存。


技術積澱----NGINX緩存


proxy_cache_path 指令包含下面這些配置:

/path/to/cache/ 指定緩存存放的磁盤目錄。

levels=1:2 設置緩存存放的目錄結構為兩級,這個也是官方推薦的設置。設置默認是一級目錄結構,實驗表明在大量緩存文件被頻繁讀取的場景,文件讀取性能會降低。

keys_zone 設置一個共享的區域,用來存放緩存的key以及元數據,用來計算定時,緩存是不是命中等信息。1M的共享區域可以存儲大約8000個key,本例子設置的10M,大約可以存儲8萬個key。

max_size 設置允許nginx緩存使用的最大磁盤空間,比如本例子中允許使用的最大空間是10G,如果不設置,表示允許使用所有的磁盤空間。如果緩存佔用達到了設置的上限,緩存管理器會自動移除最近最少使用的數據。

inactive 指定一個緩存項最大多長時間,不被使用將被刪除。本例子中設置的是60m,表示如果一個緩存項,超過60分鐘沒有被再次請求,那麼緩存管理器會自動刪除此緩存,不管緩存是不是過期。inactive 內容和緩存過期(Expired)是兩個不同的概念。Nginx不會自動刪除緩存過期的內容,Expired (stale)內容只會在Inactive時間到了後,才會被緩存管理器刪除。

use_temp_path 官方推薦設置為off,用來改變nginx默認首次緩存文件被寫入臨時文件。設置為off後,緩存文件將不會先寫入臨時文件,然後後續移動到緩存目錄,避免緩存文件被copy帶來的系統開銷。

最後proxy_cache 指令用來控制如何使用nginx緩存,如上面例子,請求滿足配置規則進入location,請求到的內容將會被緩存。

proxy_cache 也可以在直接在server指令的作用域設置,如果location沒有設置proxy_cache,那麼將直接使用server的緩存設置。


NGINX中緩存的key是什麼格式?

nginx默認的緩存key 是$scheme$proxy_host$request_uri,然後做MD5 hash。$schema是nginx內置的變量,表示http 或者https。$proxy_host,$request_uri如何理解,請看下面的例子。


技術積澱----NGINX緩存

http://www.example.org/my_image.jpg請求對於上面的配置,緩存key就應該是md5(“http://my_upstream:80/my_image.jpg”)。

大家注意到$proxy_host被用在了生成緩存key。$proxy_host如何理解呢?location中proxy_pass指令指定的名字和端口,端口默認是80。

同時nginx緩存也支持,用戶自定義緩存的key,可以通過proxy_cache_key 進行設置,比如proxy_cache_key $uri$is_args$args;

ps: $is_args 代表請求中的 ?


如何指定緩存過期時間?

要理清楚此問題,首先需要了解http請求,是如何控制緩存的以及如何校驗緩存是不是失效。

緩存控制大家最常見到的是Pragma,Cache-Control,Expires關鍵字。

http不同的版本控制緩存方式是不一樣的,我們先講http1.0,1.0時代控制比較簡單:Pragma: no-cache時,表示禁用緩存,Expires的值是一個GMT時間,表示該緩存的有效時間,但是實際使用的時候,本地時間和服務器時間可能不一致。

http1.1通過Cache-Control來控制緩存。使用Last-Modified,或者etag來校驗緩存。

首先講一下Last-Modified。服務端在返回資源時,會將該資源的最後更改時間通過Last-Modified字段返回給客戶端。客戶端下次請求時通過If-Modified-Since或者If-Unmodified-Since帶上Last-Modified,服務端檢查該時間是否與服務器的最後修改時間一致:如果一致,則返回304狀態碼,不返回資源;如果不一致則返回200和修改後的資源,並帶上新的時間,如下圖:


技術積澱----NGINX緩存


單純的以修改時間來判斷還是有缺陷,比如文件的最後修改時間變了,但內容沒變。對於這樣的情況,我們可以使用etag來處理。

etag的方式是這樣:服務器通過某個算法對資源進行計算,取得一串值(類似於文件的md5值),之後將該值通過etag返回給客戶端,客戶端下次請求時通過If-None-Match或If-Match帶上該值,服務器對該值進行對比校驗:如果一致則不要返回資源。

If-None-Match和If-Match的區別是:

If-None-Match:告訴服務器如果一致,返回狀態碼304,不一致則返回資源

If-Match:告訴服務器如果不一致,返回狀態碼412

如上http1.0、http1.1現在的http2.0,一些開發為了兼容複雜的環境,索性代碼中一併兼容。

nginx默認不支持http1.0。如果要NGINX識別Pragma。開發者需要額外配置。

nginx默認支持是1.1的緩存控制,如果請求響應Cache-Control設置為Private, No-Cache, or No-Store 或者攜帶 cookie,nginx默認行為是不會緩存結果的。同時GET,HEAD請求才有可能被緩存。

服務器端可以Cache-Control:max-age=xxx (xxx is numeric),開控制緩存的過期時間。


NGINX 可以改變緩存Cache-Control的行為嗎?


技術積澱----NGINX緩存


如上截圖,nginx通過proxy_ignore_headers 指令可以忽略Cache-Control頭部,強行設置緩存有效期是30分鐘。如果沒有設置有效期,nginx默認行為是不會緩存內容的。

緩存失效後,如何控制併發更新?

nginx提供了proxy_cache_lock 指令,這個指令打開後,如果併發請求未命中緩存(MISS),只允許一個請求到後端請求結果,其他請求等待結果,從緩存中拿數據。這個相當於一個分佈式鎖。在高併發場景非常有用。如果沒有設置的話,多個請求都會直接回源到後端。

proxy_cache_lock_age、proxy_cache_lock_timeout 可以進一步控制鎖的行為。

緩存失效後,如果觸發自動更新?


技術積澱----NGINX緩存


如上面截圖,proxy_cache_use_stale指令中增加updating,同時proxy_cache_background_update 設置為on,當一個請求 返現緩存是過期的內容或者緩存正在被更新過程中,那麼此時會先返回給客戶端一個過期的內容,同時後臺會自動更新緩存。

緩存未失效,如何手動越過緩存直接回源?

這樣的場景,我理解可能有兩種,一種是想驗證下緩存是不是正確,第二種場景強制手動更新緩存。可以通過nginx緩存提供的proxy_cache_bypass指令來實現。


技術積澱----NGINX緩存


proxy_cache_bypass告訴nginx緩存,如果請求參數或者cookie中有nocache,那麼請求將回源到後端服務,而不是優先從緩存中取,請求之後的結果會被再次緩存。如下面這個請求http://www.example.com/?nocache=true。

如何統計緩存命中率?

nginx內置的變量 $upstream_cache_status,可以獲得緩存的使用情況,開發可以將此狀態打在日誌中,或者增加到http頭部,此變量可能有的取值,MISS, BYPASS, EXPIRED, STALE, UPDATING, REVALIDATED, HIT。統計請求中緩存狀態,就可以知道緩存使用情況。

後端服務掛了,服務如何降級?

nginx緩存功能一大特點是當後端服務不能正常響應的時候,比如服務掛了,或者出現臨時出現毛刺,可以通過配置服務降級,直接從緩存中取出內容,儘管此時緩存中的內容,已經不是最新值。在某些場景下,服務降級比服務直接掛了,會帶來更好的用戶體驗。

proxy_cache_use_stale 指令可以設置服務出現問題後緩存的表現。


技術積澱----NGINX緩存


和上面同樣的配置,只是額外增加proxy_cache_use_stale 指令,如果nginx收到後端服務error,timeout,或者500,502,503,504響應的時候,緩存雖然已經過期,但是還沒有被緩存緩存管理器刪除,那麼此時nginx就可以直接給用戶返回已經過期的內容。


技術積澱----NGINX緩存


參考:

https://my.oschina.net/u/1024333/blog/495780

https://blog.csdn.net/u012375924/article/details/82806617


分享到:


相關文章: