Web緩存基礎:術語、HTTP報頭和緩存策略
什麼是緩存(caching)?
緩存(caching)是一個描述存儲可重用資源以便加快後續請求的行為的術語。有許多不同類型的緩存,每種都有其自身的特點,應用程序緩存和內存緩存由於其對特定回復的加速,都很常用。
這份指南的主要講述的Web緩存是一種不同類型的緩存。Web緩存是HTTP協議的一個核心特性,它能最小化網路流量,並且提升用戶所感知的整個系統響應速度。內容從伺服器到瀏覽器的傳輸過程中,每個層面都可以找到緩存的身影。
Web緩存根據特定的規則緩存相應HTTP請求的響應。對於緩存內容的後續請求便可以直接由緩存滿足而不是重新發送請求到Web伺服器。
好處
有效的緩存技術不僅可以幫助用戶,還可以幫助內容的提供者。緩存對內容分髮帶來的好處有:
- 減少網路開銷:內容可以在從內容提供者到內容消費者網路路徑之間的許多不同的地方被緩存。當內容在距離內容消費者更近的地方被緩存時,由於緩存的存在,請求將不會消耗額外的網路資源。
- 加快響應速度:由於並不是必須通過整個網路往返,緩存可以使內容的獲得變得更快。緩存放在距用戶更近的地方,例如瀏覽器緩存,使得內容的獲取幾乎是瞬時的。
- 在同樣的硬體上提高速度:對於保存原始內容的伺服器來說,更多的性能可以通過允許激進的緩存策略從硬體上壓榨出來。內容擁有者們可以利用分發路徑上某個強大的伺服器來應對特定內容負載的衝擊。
- 網路中斷時內容依舊可用:使用某種策略,緩存可以保證在原始伺服器變得不可用時,相應的內容對用戶依舊可用。
術語
在面對緩存時,您可能對一些經常遇到的術語可能不太熟悉。一些常見的術語如下:
- 原始伺服器:原始伺服器是內容的原始存放地點。如果您是Web伺服器管理員,它就是您所管理的機器。它負責為任何不能從緩存中得到的內容進行回復,並且負責設置所有內容的緩存策略。
- 緩存命中率:一個緩存的有效性依照緩存的命中率進行度量。它是可以從緩存中得到數據的請求數與所有請求數的比率。緩存命中率高意味著有很高比例的數據可以從緩存中獲得。這通常是大多數管理員想要的結果。
- 新鮮度:新鮮度用來描述一個緩存中的項目是否依舊適合返回給客戶端。緩存中的內容只有在由緩存策略指定的新鮮期內才會被返回。
- 過期內容:緩存中根據緩存策略的新鮮期設置已過期的內容。過期的內容被標記為「陳舊」。通常,過期內容不能用於回復客戶端的請求。必須重新從原始伺服器請求新的內容或者至少驗證緩存的內容是否仍然準確。
- 校驗:緩存中的過期內容可以驗證是否有效以便刷新過期時間。驗證過程包括聯繫原始伺服器以檢查緩存的數據是否依舊代表了最近的版本。
- 失效:失效是依據過期日期從緩存中移除內容的過程。當內容在原始伺服器上已被改變時就必須這樣做,緩存中過期的內容會導致客戶端發生問題。
還有許多其他的緩存術語,不過上面的這些應該能幫助您開始。
什麼能被緩存?
某些特定的內容比其他內容更容易被緩存。對大多數站點來說,一些適合緩存的內容如下:
- Logo和商標圖像
- 普通的不變化的圖像(例如,導航圖標)
- CSS樣式表
- 普通的Javascript文件
- 可下載的內容
- 媒體文件
這些文件更傾向於不經常改變,所以長時間的對它們進行緩存能獲得好處。
一些項目在緩存中必須加以注意:
- HTML頁面
- 會替換改變的圖像
- 經常修改的Javascript和CSS文件
- 需要有認證後的cookies才能訪問的內容
一些內容從來不應該被緩存:
- 與敏感信息相關的資源(銀行數據,等)
- 用戶相關且經常更改的數據
除上面的通用規則外,通常您需要指定一些規則以便於更好地緩存不同種類的內容。例如,如果登錄的用戶都看到的是同樣的網站視圖,就應該在任何地方緩存這個頁面。如果登錄的用戶會在一段時間內看到站點中用戶特定的視圖,您應該讓用戶的瀏覽器緩存該數據而不應讓任何中介節點緩存該視圖。
Web內容緩存的位置
Web內容會在整個分發路徑中的許多不同的位置被緩存:
- 瀏覽器緩存:Web瀏覽器自身會維護一個小型緩存。典型地,瀏覽器使用一種策略指示緩存最重要的內容。這可能是用戶相關的內容或可能會再次請求且下載代價較高。
- 中間緩存代理:任何在客戶端和您的基礎架構之間的伺服器都可以按期望緩存一些內容。這些緩存可能由ISP(網路服務提供者)或者其他獨立組織提供。
- 反向緩存:您的伺服器基礎架構可以為後端的服務實現自己的緩存。如果實現了緩存,那麼便可以在處理請求的位置返回相應的內容而不用每次請求都使用後端服務。
上面的這些位置通常都可以根據它們自身的緩存策略和內容源的緩存策略緩存一些相應的內容。
緩存頭部
緩存策略依賴於兩個不同的因素。所緩存的實體本身需要決定是否應該緩存可接受的內容。它可以只緩存部分可以緩存的內容,但不能緩存超過限制的內容。
緩存行為主要由緩存策略決定,而緩存策略由內容擁有者設置。這些策略主要通過特定的HTTP頭部來清晰地表達。
經過幾個不同HTTP協議的變化,出現了一些不同的針對緩存方面的頭部,它們的複雜度各不相同。下面列出了那些你也許應該注意的:
Expires
:儘管使用範圍相當有限,但Expires
頭部是非常簡潔明了的。通常它設置一個未來的時間,內容會在此時間過期。這時,任何對同樣內容的請求都應該回到原始伺服器處。這個頭部或許僅僅最適合回退模式(fall back)。Cache-Control
:這是Expires
的一個更加現代化的替換物。它已被很好的支持,且擁有更加靈活的實現。在大多數案例中,它比Expires
更好,但同時設置兩者的值也無妨。稍後我們將討論您可以設置的Cache-Control
的詳細選項。ETag
:ETag
用於緩存驗證。源伺服器可以在首次服務一個內容時為該內容提供一個獨特的ETag
。當一個緩存需要驗證這個內容是否即將過期,他會將相應的ETag
發送回伺服器。源伺服器或者告訴緩存內容是一致的,或者發送更新後的內容(帶著新的ETag
)。Last-Modified
:這個頭部指明了相應的內容最後一次被修改的時間。它可能會作為保證內容新鮮度的驗證策略的一部分被使用。Content-Length
:儘管並沒有在緩存中明確涉及,Content-Length
頭部在設置緩存策略時很重要。某些軟體如果不提前獲知內容的大小以留出足夠空間,則會拒絕緩存該內容。Vary
:緩存系統通常使用請求的主機和路徑作為存儲該資源的鍵。當判斷一個請求是否是請求同樣內容時,Vary
頭部可以被用來提醒緩存系統需要注意另一個附加頭部。它通常被用來告訴緩存系統同樣注意Accept-Encoding
頭部,以便緩存系統能夠區分壓縮和未壓縮的內容。
Vary頭部的隱語
Vary
頭部提供給您存儲同一個內容的不同版本的能力,代價是降低了緩存的容量。
在使用Accept-Encoding
時,設置Vary
頭部允許明確區分壓縮和未壓縮的內容。這在服務某些不能處理壓縮數據的瀏覽器時很重要,它可以保證基本的可用性。Vary
的一個典型的值是Accept-Encoding
,它只有兩到三個可選的值。
一開始看上去User-Agent
這樣的頭部可以用於區分移動瀏覽器和桌面瀏覽器,以便您的站點提供差異化的服務。但User-Agent
字元串是非標準的,結果將會造成在中間緩存中保存同一內容的許多不同版本的緩存,這會導致緩存命中率的降低。Vary
頭部應該謹慎使用,尤其是您不具備在您控制的中間緩存中使請求標準化的能力(也許可以,比如您可以控制CDN的話)。
緩存控制標誌怎樣影響緩存
上面我們提到了Cache-Control
頭部如何被用與現代緩存策略標準。能夠通過這個頭部設定許多不同的緩存指令,多個不同的指令通過逗號分隔。
一些您可以使用的指示內容緩存策略的Cache-Control
的選項如下:
no-cache
:這個指令指示所有緩存的內容在新的請求到達時必須先重新驗證,再發送給客戶端。這條指令實際將內容立刻標記為過期的,但允許通過驗證手段重新驗證以避免重新下載整個內容。no-store
:這條指令指示緩存的內容不能以任何方式被緩存。它適合在回復敏感信息時設置。public
:它將內容標記為公有的,這意味著它能被瀏覽器和其他任何中間節點緩存。通常,對於使用了HTTP驗證的請求,其回復被默認標記為private
。public
標記將會覆蓋這個設置。private
:它將內容標記為私有的。私有數據可以被用戶的瀏覽器緩存,但不能被任何中間節點緩存。它通常用於用戶相關的數據。max-age
:這個設置指示了緩存內容的最大生存期,它在最大生存期後必須在源伺服器處被驗證或被重新下載。在現代瀏覽器中這個選項大體上取代了Expires
頭部,瀏覽器也將其作為決定內容的新鮮度的基礎。這個選項的值以秒為單位表示,最大可以表示一年的新鮮期(31536000秒)。s-maxage
:這個選項非常類似於max-age
,它指明了內容能夠被緩存的時間。區別是這個選項只在中間節點的緩存中有效。結合這兩個選項可以構建更加靈活的緩存策略。must-revalidate
:它指明了由max-age
、s-maxage
或Expires
頭部指明的新鮮度信息必須被嚴格的遵守。它避免了緩存的數據在網路中斷等類似的場景中被使用。proxy-revalidate
:它和上面的選項有著一樣的作用,但只應用於中間的代理節點。在這種情況下,用戶的瀏覽器可以在網路中斷時使用過期內容,但中間緩存內容不能用於此目的。no-transform
:這個選項告訴緩存在任何情況下都不能因為性能的原因修改接收到的內容。這意味著,緩存不允許壓縮接收到的內容(沒有從原始伺服器處接收過壓縮版本的該內容)並發送。
這些選項能夠以不同的方式結合以獲得不同的緩存行為。一些互斥的值如下:
no-cache
,no-store
以及由其他前面未提到的選項指明的常用的緩存行為public
和private
如果no-store
和no-cache
都被設置,那麼no-store
會取代no-cache
。對於非授權的請求的回復,public
是隱含的設置。對於授權的請求的回復,private
選項是隱含的。他們可以通過在Cache-Control
頭部中指明相應的相反的選項以覆蓋。
開發一種緩存策略
在理想情況下,任何內容都可以被儘可能緩存,而您的伺服器只需要偶爾的提供一些驗證內容即可。但這在現實中很少發生,因此您應該嘗試設置一些明智的緩存策略,以在長期緩存和站點改變的需求間達到平衡。
常見問題
在許多情況中,由於內容被產生的方式(如根據每個用戶動態的產生)或者內容的特性(例如銀行的敏感數據),這些內容不應該被緩存。另一些許多管理員在設置緩存時可能面對的問題是外部緩存的數據未過期,但新版本的數據已經產生。
這些都是經常遇到的問題,它們會影響緩存的性能和您提供的數據的準確性。然而,我們可以通過開發提前預見這些問題的緩存策略來緩解這些問題。
一般性建議
儘管您的實際情況會指導您選擇的緩存策略,但是下面的建議能幫助您獲得一些合理的決定。
在您擔心使用哪一個特定的頭部之前,有一些特定的步驟可以幫助您提高您的緩存命中率。一些建議如下:
- 為圖像、CSS和共享的內容建立特定的文件夾:將內容放到特定的文件夾內使得您可以方便的從您的站點中的任何頁面引用這些內容。
- 使用同樣的URL來表示同樣的內容:由於緩存使用內容請求中的主機名和路徑作為鍵,因此應保證您的所有頁面中的該內容的引用方式相同,前一個建議能讓這點更加容易做到。
- 儘可能使用CSS圖像拼接:對於像圖標和導航等內容,使用CSS圖像拼接能夠減少渲染您頁面所需要的請求往返,並且允許對拼接緩存很長一段時間。
- 儘可能將主機腳本和外部資源本地化:如果您使用Javascript腳本和其他外部資源,如果上游沒有提供合適的緩存頭部,那麼您應考慮將這些內容放在您自己的伺服器上。您應該注意上游的任何更新,以便更新本地的拷貝。
- 對緩存內容收集文件摘要:靜態的內容比如CSS和Javascript文件等通常比較適合收集文件摘要。這意味著為文件名增加一個獨特的標誌符(通常是這個文件的哈希值)可以在文件修改後繞開緩存保證新的內容被重新獲取。有很多工具可以幫助您創建文件摘要並且修改HTML文檔中的引用。
對於不同的文件正確地選擇不同的頭部這件事,下面的內容可以作為一般性的參考:
- 允許所有的緩存存儲一般內容:靜態內容以及非用戶相關的內容應該在分發鏈的所有節點被緩存。這使得中間節點可以將該內容回復給多個用戶。
- 允許瀏覽器緩存用戶相關的內容:對於每個用戶的數據,通常在用戶自己的瀏覽器中緩存是可以被接受且有益的。緩存在用戶自身的瀏覽器能夠使得用戶在接下來的瀏覽中能夠瞬時讀取,但這些內容不適合在任何中間代理節點緩存。
- 將時間敏感的內容作為特例:如果您的數據是時間敏感的,那麼相對上面兩條參考,應該將這些數據作為特例,以保證過期的數據不會在關鍵的情況下被使用。例如,您的站點有一個購物車,它應該立刻反應購物車裡面的物品。依據內容的特點,可以在
Cache-Control
頭部中使用no-cache
或no-store
選項。 - 總是提供驗證器:驗證器使得過期的內容可以無需重新下載而得到刷新。設置
ETag
和Last-Modified
頭部將允許緩存向原始伺服器驗證內容,並在內容未修改時刷新該內容新鮮度以減少負載。 - 對於支持的內容設置長的新鮮期:為了更加有效的利用緩存,一些作為支持性的內容應該被設置較長的新鮮期。這通常比較適合圖像和CSS等由用戶請求用來渲染HTML頁面的內容。和文件摘要一起,設置延長的新鮮期將允許緩存長時間的存儲這些資源。如果資源發生改變,修改的文件摘要將會使緩存的數據無效並觸發對新的內容的下載。那時,新的支持的內容會繼續被緩存。
- 對父內容設置短的新鮮期:為了使得前面的模式正常工作,容器類的內容應該相應的設置短的新鮮期,或者設置不全部緩存。這通常是在其他協助內容中使用的HTML頁面。這個HTML頁面將會被頻繁的下載,使得它能快速的響應改變。支持性的內容因此可以被盡量緩存。
關鍵之處便在於達到平衡,一方面可以盡量的進行緩存,另一方面為未來保留當改變發生時從而改變整個內容的機會。您的站點應該同時具有:
- 盡量緩存的內容
- 擁有短的新鮮期的緩存內容,可以被重新驗證
- 完全不被緩存的內容
這樣做的目的便是將內容儘可能的移動到第一個分類(盡量緩存)中的同時,維持可以接受的緩存命中率。
結論
花時間確保您的站點使用了合適的緩存策略將對您的站點產生重要的影響。緩存使得您可以在保證服務同樣內容的同時減少帶寬的使用。您的伺服器因此可以靠同樣的硬體處理更多的流量。或許更重要的是,客戶們能在您的網站中獲得更快的體驗,這會使得他們更願意頻繁的訪問您的站點。儘管有效的Web緩存並不是銀彈,但設置合適的緩存策略會使您以最小的代價獲得可觀的收穫。
作者: Justin Ellingwood 譯者:wwy-hust 校對:wxy 推薦:royaso
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive