記錄 ---- Web緩存

Web緩存

Web 緩存是能夠自動保存常見文檔副本的HTTP設備。當Web請求抵達緩存時,若是本地有「已緩存的」副本,就能夠從本地存儲設備而不是原始服務器中提取這個文檔。
算法

使用緩存有下列優勢:
瀏覽器

  • 緩存減小了冗餘的數據傳輸,節省了你的網絡費用;
  • 緩存緩解了網絡瓶頸的問題,不須要更多的帶寬就可以更快地加載頁面;
  • 緩存下降了對原始服務器的要求,服務器能夠更快地響應,避免過載的出現;
  • 緩存下降了距離時延,由於從較遠的地方加載頁面會更慢一些;

冗餘的數據傳輸

有不少客戶端訪問一個流行的原始服務器頁面時,服務器會屢次傳輸同一份文檔,每次傳送給一個客戶端。一些相同的字節會在網絡中一遍遍地傳輸。這些冗餘的數據傳輸會耗盡昂貴的網絡帶寬,下降傳輸速度,加劇 Web 服務器的負載。有了緩存,就能夠保留第一條服務器響應的副本,後繼請求就能夠由緩存的副原本應對了,這樣能夠減小那些流入/流出原始服務器的、被浪費掉了的重複流量。
緩存

帶寬瓶頸:緩存還能夠緩解網絡的瓶頸問題。不少網絡爲本地網絡客戶端提供的帶寬比爲遠程服務器提供的帶寬要寬。客戶端會以路徑上最慢的網速訪問服務器。若是客戶端從一個快速局域網的緩存中獲得了一份副本,那麼緩存就能夠提升性能——尤爲是要傳輸比較大的文件時。
安全

瞬間擁塞:緩存在破壞瞬間擁塞(Flash Crowds)時顯得很是重要。突發事件使不少人幾乎同時去訪問一個Web文檔時,就會出現瞬間擁塞。由此形成的過多流量峯值可能會使網絡和Web服務器產生災難性的崩潰。

距離時延:即便帶寬不是問題,距離也可能成爲問題。每臺網絡路由器都會增長因特網流量的時延。即便客戶端和服務器之間沒有太多的路由器,光速自身也會形成顯著的時延。
服務器

命中和未命中

緩存沒法保存世界上每份文檔的副本。能夠用已有的副本爲某些到達緩存的請求提供服務,這被稱爲緩存命中(cache hit)。其餘一些到達緩存的請求可能會因爲沒有副本可用,而被轉發給原始服務器,這被稱爲緩存未命中(cache miss)。
網絡

再驗證

原始服務器的內容可能會發生變化,緩存要不時對其進行檢測,看看它們保存的副本是否還是服務器上最新的副本。這些"新鮮度檢測"被稱爲HTTP再驗證(revalidation)。爲了有效地進行再驗證,HTTP定義了一些特殊的請求,不用從服務器上獲取整個對象,就能夠快速檢測出內容是不是最新的。緩存能夠在任意時刻,以任意的頻率對副本進行再驗證。但因爲緩存中一般會包含數百萬的文檔,並且網絡帶寬是很珍貴的,因此大部分緩存只有在客戶端發起請求,而且副本舊得足以須要檢測的時候,纔會對副本進行再驗證。緩存對緩存的副本進行再驗證時,會向原始服務器發送一個小的再驗證請求。若是內容沒有變化,服務器會以一個小的"304 Not Modified"進行響應。只要緩存知道副本仍然有效,就會再次將副本標識爲暫時新鮮的,並將副本提供給客戶端這被稱做再驗證命中(revalidate hit)或緩慢命中(slow hit)。這種方式確實要與原始服務器進行覈對,因此會比單純的緩存命中要慢,但它沒有從服務器中獲取對象數據,因此要比緩存未命中快一些。HTTP爲咱們提供了幾個用來對已緩存對象進行再驗證的工具,但最經常使用的是"If-Modified-Since"首部。將這個首部添加到GET請求中去,就能夠告訴服務器,只有在緩存了對象的副本以後,又對其進行了修改的狀況下,才發送此對象。
數據結構

這裏列出了在3種狀況下(服務器內容未被修改,服務器內容已被修改,或者服務器上的對象被刪除了)服務器收到"GET If-Modified-Since"請求時會發生的狀況:
工具

  • 再驗證命中:若是服務器對象未被修改,服務器會向客戶端發送一個小的"HTTP 304 Not Modified"響應;
  • 再驗證未命中:若是服務器對象與已緩存副本不一樣,服務器向客戶端發送一條普通的、帶有完整內容的"HTTP 200 OK"響應;
  • 對象被刪除:若是服務器對象已經被刪除了,服務器就回送一個"404 Not Found"響應,緩存也會將其副本刪除。

命中率

由緩存提供服務的請求所佔的比例被稱爲緩存命中率(cache hit rate,或稱爲緩存命中比例),有時也被稱爲文檔命中率(document hit rate)。命中率在0到1之間,但一般是用百分數來描述的。緩存的管理者但願緩存命中率接近100%。而實際獲得的命中率則與緩存的大小、緩存用戶興趣點的類似性、緩存數據的變化或個性化頻率,以及如何配置緩存有關,命中率很難預測。緩存的好處是,即便是中等規模的緩存,其所包含的常見文檔也足以顯著地提升性能、減小流量了。緩存會努力確保將有用的內容保存在緩存中。
性能

字節命中率

因爲文檔並不全是同一尺寸的,因此文檔命中率並不能說明一切。有些大型對象被訪問的次數可能較少,但因爲尺寸的緣由,對整個數據流量的貢獻卻更大。所以,有些人更願意使用字節命中率(byte hit rate)做爲度量值(尤爲那些按流量字節付費的人!)。字節命中率表示的是緩存提供的字節在傳輸的全部字節中所佔的比例。經過這種度量方式,能夠得知節省流量的程度。100%的字節命中率說明每一個字節都來自緩存,沒有流量流到因特網上去。文檔命中率和字節命中率對緩存性能的評估都是頗有用的。文檔命中率說明阻止了多少通往外部網絡的Web事務。事務有一個一般都很大的固定時間成分(好比,創建一條到服務器的TCP鏈接),提升文檔命中率對下降總體延遲(時延)頗有好處。字節命中率說明阻止了多少字節傳向因特網。提升字節命中率對節省帶寬頗有利。
設計

區分命中和未命中的狀況

不幸的是,HTTP沒有爲用戶提供一種手段來區分響應是緩存命中的,仍是訪問原始服務器獲得的。在這兩種狀況下,響應碼都是"200 OK",說明響應有主體部分。有些商業代理緩存會在Via首部附加一些額外信息,以描述緩存中發生的狀況。客戶端有一種方法能夠判斷響應是否來自緩存,就是使用Date首部。將響應中Date首部的值與當前時間進行比較,若是響應中的日期值比較早,客戶端一般就能夠認爲這是一條緩存的響應。客戶端也能夠經過Age首部來檢測緩存的響應,經過這個首部能夠分辨出這條響應的使用期。

緩存的拓撲結構

緩存能夠是單個用戶專用的,也能夠是數千名用戶共享的。專用緩存被稱爲私有緩存(private cache)。私有緩存是我的的緩存,包含了單個用戶最經常使用的頁面。共享的緩存被稱爲公有緩存(public cache)。公有緩存中包含了某個用戶團體的經常使用頁面。

私有緩存

私有緩存不須要很大的動力或存儲空間,這樣就能夠將其作得很小,很便宜。Web瀏覽器中有內建的私有緩存——大多數瀏覽器都會將經常使用文檔緩存在你我的電腦的磁盤和內存中,而且容許用戶去配置緩存的大小和各類設置。

公有代理緩存

公有緩存是特殊的共享代理服務器,被稱爲緩存代理服務器(caching proxy server),或者更常見地被稱爲代理緩存(proxy cache)。代理緩存會從本地緩存中提供文檔,或者表明用戶與服務器進行聯繫。公有緩存會接受來自多個用戶的訪問,因此經過它能夠更好地減小冗餘流量。

代理緩存的層次結構

在實際中,實現層次化(hierarchy)的緩存是頗有意義的,在這種結構中,在較小緩存中未命中的請求會被導向較大的父緩存(parent cache),由它來爲剩下的那些"提煉過的"流量提供服務。

網狀緩存、內容路由和對等緩存

有些網絡結構會構建複雜的網狀緩存(cache mesh),而不是簡單的緩存層次結構。網狀緩存中的代理緩存之間會以更加複雜的方式進行對話,作出動態的緩存通訊決策,決定與哪一個父緩存進行對話,或者決定完全繞開緩存,直接鏈接原始服務器。這種代理緩存會決定選擇何種路由對內容進行訪問、管理和傳送,所以可將其稱爲內容路由器(content router)。緩存之間這些更爲複雜的關係容許不一樣的組織互爲對等(peer)實體,將它們的緩存鏈接起來以實現雙贏。提供可選的對等支持的緩存被稱爲兄弟緩存(sibling cache)。HTTP並不支持兄弟緩存,因此人們經過一些協議對HTTP進行了擴展,好比因特網緩存協議(Internet Cache Protocol,ICP)和超文本緩存協議(HyperText Caching Protocol,HTCP)。

網狀緩存中爲內容路由設計的緩存(除了其餘任務以外)要完成下列全部功能:

  • 根據URL在父緩存或原始服務器之間進行動態選擇;
  • 根據URL動態地選擇一個特定的父緩存;
  • 前往父緩存以前,在本地緩存中搜索已緩存的副本;
  • 容許其餘緩存對其緩存的部份內容進行訪問,但不容許因特網流量經過它們的緩存。

緩存的處理步驟

現代的商業化代理緩存至關地複雜。這些緩存構建得很是高效,能夠支持HTTP和其餘一些技術的各類高級特性。但除了一些微妙的細節以外,Web緩存的基本工做原理大多很簡單。對一條"HTTP GET"報文的基本緩存處理過程包括7個步驟:

  • 接收---緩存從網絡中讀取抵達的請求報文;
  • 解析---緩存對報文進行解析,提取出URL和各類首部;
  • 查詢---緩存查看是否有本地副本可用,若是沒有,就獲取一份副本(並將其保存在本地);
  • 新鮮度檢測---緩存查看已緩存副本是否足夠新鮮,若是不是,就詢問服務器是否有任何更新;
  • 建立響應---緩存會用新的首部和已緩存的主體來構建一條響應報文;
  • 發送---緩存經過網絡將響應發回給客戶端;
  • 日誌---緩存可選地建立一個日誌文件條目來描述這個事務。

接收

在第一步中,緩存檢測到一條網絡鏈接上的活動,讀取輸入數據。高性能的緩存會同時從多條輸入鏈接上讀取數據,在整條報文抵達以前開始對事務進行處理。

解析

接下來,緩存將請求報文解析爲片段,將首部的各個部分放入易於操做的數據結構中。這樣,緩存軟件就更容易處理首部字段並修改它們了。

查詢

在第三步中,緩存獲取了URL,查找本地副本。本地副本可能存儲在內存、本地磁盤,甚至附近的另外一臺計算機中。專業級的緩存會使用快速算法來肯定本地緩存中是否有某個對象。若是本地沒有這個文檔,它能夠根據情形和配置,到原始服務器或父代理中去取,或者返回一條錯誤信息。已緩存對象中包含了服務器響應主體和原始服務器響應首部,這樣就會在緩存命中時返回正確的服務器首部。已緩存對象中還包含了一些元數據(metadata),用來記錄對象在緩存中停留了多長時間,以及它被用過多少次等。

新鮮度檢測

HTTP經過緩存將服務器文檔的副本保留一段時間。在這段時間裏,都認爲文檔是"新鮮的",緩存能夠在不聯繫服務器的狀況下,直接提供該文檔。但一旦已緩存副本停留的時間太長,超過了文檔的新鮮度限值(freshness limit),就認爲對象"過期"了,在提供該文檔以前,緩存要再次與服務器進行確認,以查看文檔是否發生了變化。客戶端發送給緩存的全部請求首部自身均可以強制緩存進行再驗證,或者徹底避免驗證,這使得事情變得更加複雜了。HTTP有一組很是複雜的新鮮度檢測規則,緩存產品支持的大量配置選項,以及與非HTTP新鮮度標準進行互通的須要則使問題變得更加嚴重了。本章其他的大部分篇幅都用於解釋新鮮度的計算問題。

建立響應

咱們但願緩存的響應看起來就像來自原始服務器的同樣,緩存將已緩存的服務器響應首部做爲響應首部的起點。而後緩存對這些基礎首部進行了修改和擴充。緩存負責對這些首部進行改造,以便與客戶端的要求相匹配。好比,服務器返回的多是一條"HTTP/1.0"響應(甚至是"HTTP/0.9"響應),而客戶端期待的是一條"HTTP/1.1"響應,在這種狀況下,緩存必須對首部進行相應的轉換。緩存還會向其中 插入新鮮度信息(Cache-Control、Age以及Expires首部),並且一般會包含一個Via首部來講明請求是由一個代理緩存提供的。注意,緩存不該該調整Date首部。Date首部表示的是原始服務器最初產生這個對象的日期。

發送

一旦響應首部準備好了,緩存就將響應回送給客戶端。和全部代理服務器同樣,代理緩存要管理與客戶端之間的鏈接。高性能的緩存會盡力高效地發送數據,一般能夠避免在本地緩存和網絡I/O緩衝區之間進行文檔內容的複製。

日誌

大多數緩存都會保存日誌文件以及與緩存的使用有關的一些統計數據。每一個緩存事務結束以後,緩存都會更新緩存命中和未命中數目的統計數據(以及其餘相關的度量值),並將條目插入一個用來顯示請求類型、URL和所發生事件的日誌文件。

保持副本的新鮮

可能不是全部的已緩存副本都與服務器上的文檔一致。畢竟,這些文檔會隨着時間發生變化。報告可能每月都會變化。在線報紙天天都會發生變化。財經數據可能每過幾秒鐘就會發生變化。若是緩存提供的老是老的數據,就會變得毫無用處。已緩存數據要與服務器數據保持一致。HTTP有一些簡單的機制能夠在不要求服務器記住有哪些緩存擁有其文檔副本的狀況下,保持已緩存數據與服務器數據之間充分一致。HTTP將這些簡單的機制稱爲文檔過時(document expiration)和服務器再驗證(server revalidation)。

文檔過時

經過特殊的HTTP Cache-Control首部和Expires首部,HTTP讓原始服務器向每一個文檔附加了一個"過時日期"。這些首部說明了在多長時間內能夠將這些內容視爲新鮮的。在緩存文檔過時以前,緩存能夠以任意頻率使用這些副本,而無需與服務器聯繫——固然,除非客戶端請求中包含有阻止提供已緩存或未驗證資源的首部。但一旦已緩存文檔過時,緩存就必須與服務器進行覈對,詢問文檔是否被修改過,若是被修改過,就要獲取一份新鮮(帶有新的過時日期)的副本。

過時日期和使用期

服務器用"HTTP/1.0+"的Expires首部或"HTTP/1.1"的"Cache-Control: max-age"響應首部來指定過時日期,同時還會帶有響應主體。Expires首部和"Cache-Control: max-age"首部所作的事情本質上是同樣的,但因爲Cache-Control首部使用的是相對時間而不是絕對日期,因此咱們更傾向於使用比較新的Cache-Control首部。絕對日期依賴於計算機時鐘的正確設置。

過時響應首部

首部 描述
Cache-Control: max-age=484200 max-age值定義了文檔的最大使用期——從第一次生成文檔到文檔再也不新鮮、沒法使用爲止,最大的合法生存時間(以秒爲單位)
Expires: Fri, 05 Jul 2002, 05:00:00 GMT 指定一個絕對的過時日期。若是過時日期已通過了,就說明文檔再也不新鮮了

服務器再驗證

僅僅是已緩存文檔過時了並不意味着它和原始服務器上目前處於活躍狀態的文檔有實際的區別;這只是意味着到了要進行覈對的時間了。這種狀況被稱爲"服務器再驗證",說明緩存須要詢問原始服務器文檔是否發生了變化。緩存並不必定要爲每條請求驗證文檔的有效性——只有在文檔過時時它才須要與服務器進行再驗證。這樣不會提供陳舊的內容,還能夠節省服務器的流量,並擁有更好的用戶響應時間。

  • 若是再驗證顯示內容發生了變化,緩存會獲取一份新的文檔副本,並將其存儲在舊文檔的位置上,而後將文檔發送給客戶端。
  • 若是再驗證顯示內容沒有發生變化,緩存只須要獲取新的首部,包括一個新的過時日期,並對緩存中的首部進行更新就好了。

HTTP協議要求行爲正確的緩存返回下列內容之一:

  • "足夠新鮮"的已緩存副本;
  • 與服務器進行過再驗證,確認其仍然新鮮的已緩存副本;
  • 若是須要與之進行再驗證的原始服務器出故障了,就返回一條錯誤報文 ;
  • 附有警告信息說明內容可能不正確的已緩存副本。

用條件方法進行再驗證

HTTP的條件方法能夠高效地實現再驗證。HTTP容許緩存向原始服務器發送一個"條件GET",請求服務器只有在文檔與緩存中現有的副本不一樣時,纔回送對象主體。經過這種方式,將新鮮度檢測和對象獲取結合成了單個條件GET。向GET請求報文中添加一些特殊的條件首部,就能夠發起條件GET。只有條件爲真時,Web服務器纔會返回對象。HTTP定義了5個條件請求首部。對緩存再驗證來講最有用的2個首部是If-Modified-Since和If-None-Match。全部的條件首部都之前綴"If-"開頭。

緩存再驗證中使用的條件請求首部:

首部 描述
If-Modified-Since:<date> 若是從指定日期以後文檔被修改過了,就執行請求的方法。能夠與Last-Modified服務器響應首部配合使用,只有在內容被修改後與已緩存版本有所不一樣的時候纔去獲取內容
If-None-Match:<tags> 服務器能夠爲文檔提供特殊的標籤,而不是將其與最近修改日期相匹配,這些標籤就像序列號同樣。若是已緩存標籤與服務器文檔中的標籤有所不一樣,If-None-Match首部就會執行所請求的方法

If-Modified-Since:Date再驗證

最多見的緩存再驗證首部是If-Modified-Since。If-Modified-Since再驗證請求一般被稱爲IMS請求。只有自某個日期以後資源發生了變化的時候,IMS請求才會指示服務器執行請求:

  • 若是自指定日期後,文檔被修改了,If-Modified-Since條件就爲真,一般GET就會成功執行。攜帶新首部的新文檔會被返回給緩存,新首部除了其餘信息以外,還包含了一個新的過時日期。
  • 若是自指定日期後,文檔沒被修改過,條件就爲假,會向客戶端返回一個小的"304 Not Modified"響應報文,爲了提升有效性,不會返回文檔的主體。這 些首部是放在響應中返回的,但只會返回那些須要在源端更新的首部。好比,Content-Type首部一般不會被修改,因此一般不須要發送。通常會發送一個新的過時日期。

If-Modified-Since首部能夠與Last-Modified服務器響應首部配合工做。原始服務器會將最後的修改日期附加到所提供的文檔上去。當緩存要對已緩存文檔進行再驗證時,就會包含一個If-Modified-Since首部,其中攜帶有最後修改已緩存副本的日期。若是在此期間內容被修改了,最後的修改日期就會有所不一樣,原始服務器就會回送新的文檔。不然,服務器會注意到緩存的最後修改日期與服務器文檔當前的最後修改日期相符,會返回一個"304 Not Modified"響應。注意,有些Web服務器並無將If-Modified-Since做爲真正的日期來進行比對。相反,它們在IMS日期和最後修改日期之間進行了字符串匹配。這樣獲得的語義就是"若是最後的修改不是在這個肯定的日期進行的",而不是"若是在這個日期以後沒有被修改過"。將最後修改日期做爲某種序列號使用時,這種替代語義可以很好地識別出緩存是否過時,但這會妨礙客戶端將If-Modified-Since首部用於真正基於時間的一些目的。

If-None-Match:實體標籤再驗證

有些狀況下僅使用最後修改日期進行再驗證是不夠的。

  • 有些文檔可能會被週期性地重寫(好比,從一個後臺進程中寫入),但實際包含的數據經常是同樣的。儘管內容沒有變化,但修改日期會發生變化。
  • 有些文檔可能被修改了,但所作修改並不重要,不須要讓世界範圍內的緩存都重裝數據(好比對拼寫或註釋的修改)。
  • 有些服務器沒法準確地斷定其頁面的最後修改日期。
  • 有些服務器提供的文檔會在亞秒間隙發生變化(好比,實時監視器),對這些服務器來講,以一秒爲粒度的修改日期可能就不夠用了。

爲了解決這些問題,HTTP容許用戶對被稱爲實體標籤(ETag)的"版本標識符"進行比較。實體標籤是附加到文檔上的任意標籤(引用字符串)。它們可能包含了文檔的序列號或版本名,或者是文檔內容的校驗和及其餘指紋信息。當發佈者對文檔進行修改時,能夠修改文檔的實體標籤來講明這個新的版本。這樣,若是實體標籤被修改了,緩存就能夠用If-None-Match條件首部來GET文檔的新副本了。

強弱驗證器

緩存能夠用實體標籤來判斷,與服務器相比,已緩存版本是否是最新的(與使用最近修改日期的方式很像)。從這個角度來看,實體標籤和最近修改日期都是緩存驗證器(cache validator)。有時,服務器但願在對文檔進行一些非實質性或不重要的修改時,不要使全部的已緩存副本都失效。"HTTP/1.1"支持"弱驗證器",若是隻對內容進行了少許修改,就容許服務器聲明那是"足夠好"的等價體。只要內容發生了變化,強驗證器就會變化。弱驗證器容許對一些內容進行修改,但內容的主要含義發生變化時,一般它仍是會變化的。有些操做不能用弱驗證器來實現(好比有條件地獲取部份內容),因此,服務器會用前綴"W/"來標識弱驗證器。無論相關的實體值以何種方式發生了變化,強實體標籤都要發生變化。而相關實體在語義上發生了比較重要的變化時,弱實體標籤也應該發生變化。注意,原始服務器必定不能爲兩個不一樣的實體重用一個特定的強實體標籤值,或者爲兩個語義不一樣的實體重用一個特定的弱實體標籤值。緩存條目可能會留存任意長的時間,與其過時時間無關,有人可能但願當緩存驗證條目時,絕對不會再次使用在過去某一時刻得到的驗證器,這種願望可能不太現實。

實體標籤和最近修改日期

若是服務器回送了一個實體標籤,"HTTP/1.1"客戶端就必須使用實體標籤驗證器。若是服務器只回送了一個Last-Modified值,客戶端就可使用If-Modified-Since驗證。若是實體標籤和最後修改日期都提供了,客戶端就應該使用這兩種再驗證方案,這樣"HTTP/1.0"和"HTTP/1.1"緩存就均可以正確響應了。除非"HTTP/1.1"原始服務器沒法生成實體標籤驗證器,不然就應該發送一個出去,若是使用弱實體標籤有優點的話,發送的可能就是個弱實體標籤,而不是強實體標籤。並且,最好同時發送一個最近修改值。若是"HTTP/1.1"緩存或服務器收到的請求既帶有If-Modified-Since,又帶有實體標籤條件首部,那麼只有這兩個條件都知足時,才能返回"304 Not Modified"響應。

控制緩存的能力

服務器能夠經過 HTTP 定義的幾種方式來指定在文檔過時以前能夠將其緩存多長時間。按照優先級遞減的順序,服務器能夠:

  • 附加一個"Cache-Control: no-store"首部到響應中去;
  • 附加一個"Cache-Control: no-cache"首部到響應中去;
  • 附加一個"Cache-Control: must-revalidate"首部到響應中去;
  • 附加一個"Cache-Control: max-age"首部到響應中去;
  • 附加一個"Expires"日期首部到響應中去;
  • 不附加過時信息,讓緩存肯定本身的過時日期。

no-Store 與 no-Cache 響應首部

"HTTP/1.1"提供了幾種限制對象緩存,或限制提供已緩存對象的方式,以維持對象的新鮮度。no-store首部和no-cache首部能夠防止緩存提供未經證明的已緩存對象:

  • 標識爲no-store的響應會禁止緩存對響應進行復制。緩存一般會像非緩存代理服務器同樣,向客戶端轉發一條no-store響應,而後刪除對象。
  • 標識爲no-cache的響應其實是能夠存儲在本地緩存區中的。只是在與原始服務器進行新鮮度再驗證以前,緩存不能將其提供給客戶端使用。這個首部使用do-not-serve-from-cache-without-revalidation這個名字會更恰當一些。
  • "HTTP/1.1"中提供Pragma: no-cache首部是爲了兼容於"HTTP/1.0+"。除了與只理解"Pragma: no-cache"的"HTTP/1.0"應用程序進行交互時,"HTTP 1.1"應用程序都應該使用"Cache-Control: no-cache"。

max-age響應首部

"Cache-Control: max-age"首部表示的是從服務器將文檔傳來之時起,能夠認爲此文檔處於新鮮狀態的秒數(Cache-Control: max-age=3600)。還有一個s-maxage首部(注意maxage的中間沒有連字符),其行爲與max-age相似,但僅適用於共享(公有)緩存(Cache-Control: s-maxage=3600)。服務器能夠請求緩存不要緩存文檔,或者將最大使用期設置爲零,從而在每次訪問的時候都進行刷新(Cache-Control: max-age=0)。

Expires響應首部

不推薦使用Expires首部,它指定的是實際的過時日期而不是秒數。HTTP設計者後來認爲,因爲不少服務器的時鐘都不一樣步,或者不正確,因此最好仍是用剩餘秒數,而不是絕對時間來表示過時時間。能夠經過計算過時值和日期值之間的秒數差來計算相似的新鮮生存期(Expires: Fri, 05 Jul 2002, 05:00:00 GMT)。有些服務器還會回送一個"Expires:0"響應首部,試圖將文檔置於永遠過時的狀態,但這種語法是非法的,可能給某些軟件帶來問題。應該試着支持這種結構的輸入,但不該該產生這種結構的輸出。

must-revalidate 響應首部

能夠配置緩存,使其提供一些陳舊(過時)的對象,以提升性能。若是原始服務器但願緩存嚴格遵照過時信息,能夠在原始響應中附加一個"Cache-Control: must-revalidate"首部。"Cache-Control: must-revalidate"響應首部告訴緩存,在事先沒有跟原始服務器進行再驗證的狀況下,不能提供這個對象的陳舊副本。緩存仍然能夠隨意提供新鮮的副本。若是在緩存進行must-revalidate新鮮度檢查時,原始服務器不可用,緩存就必須返回一條"504 Gateway Timeout"錯誤。

試探性過時

若是響應中沒有"Cache-Control: max-age"首部,也沒有Expires首部,緩存能夠計算出一個試探性最大使用期。可使用任意算法,但若是獲得的最大使用期大於24小時,就應該向響應首部添加一個Heuristic Expiration Warning(試探性過時警告,警告13)首部。不多有瀏覽器會爲用戶提供這種警告信息。LM-Factor算法是一種很經常使用的試探性過時算法,若是文檔中包含了最後修改日期,就可使用這種算法。LM-Factor算法將最後修改日期做爲依據,來估計文檔有多麼易變。實際的LM-Factor算法會計算緩存與服務器對話的時間跟服務器聲明文檔最後被修改的時間之間的差值,取這個間隔時間的一部分,將其做爲緩存中的新鮮度持續時間。一般人們會爲試探性新鮮週期設置上限,這樣它們就不會變得太大了。儘管比較保守的站點會將這個值設置爲一天,但一般站點會將其設置爲一週。若是最後修改日期也沒有的話,緩存就沒什麼信息可利用了。緩存一般會爲沒有任何新鮮週期線索的文檔分配一個默認的新鮮週期(一般是一個小時或一天)。有時,比較保守的緩存會將這種試探性新鮮生存期設置爲0,強制緩存在每次將其提供給客戶端以前,都去驗證一下這些數據仍然是新鮮的。與試探性新鮮計算有關的最後一點是——它們可能比你想象的要常見得多。不少原始服務器仍然不會產生Expires和max-age首部。選擇緩存過時的默認時間時要特別當心!

LM-Factor算法的邏輯:

  • 若是已緩存文檔最後一次修改發生在好久之前,它可能會是一份穩定的文檔,不太會忽然發生變化,所以將其繼續保存在緩存中會比較安全。
  • 若是已緩存文擋最近被修改過,就說明它極可能會頻繁地發生變化,所以在與服務器進行再驗證以前,只應該將其緩存很短一段時間。

客戶端的新鮮度限制

Web 瀏覽器都有刷新(Refresh)或 重載(Reload)按鈕,能夠強制對瀏覽器或代理緩存中可能過時的內容進行刷新。刷新按鈕會發佈一個附加了Cache-Control請求首部的GET請求,這個請求會強制進行再驗證,或者無條件地從服務器獲取文檔。刷新的確切行爲取決於特定的瀏覽器、文檔以及攔截緩存的配置。客戶端能夠用Cache-Control請求首部來強化或放鬆對過時時間的限制。有些應用程序對文檔的新鮮度要求很高(好比人工刷新按鈕),對這些應用程序來講,客戶端能夠用Cache-Control首部使過時時間更嚴格。另外一方面,做爲提升性能、可靠性或開支的一種折衷方式,客戶端可能會放鬆新鮮度要求。

Cache-Control請求指令:

指令 目的
Cache-Control: max-stale = (s) 緩存能夠隨意提供過時的文件。若是指定了參數(s),在這段時間內,文檔就不能過時。這條指令放鬆了緩存的規則
Cache-Control: min-fresh=(s) 至少在將來(s)秒內文檔要保持新鮮。這就使緩存規則更加嚴格了
Cache-Control: max-age = (s) 緩存沒法返回緩存時間長於(s)秒的文檔。這條指令會使緩存規則更加嚴格,除非同時還發送max-stale指令,在這種狀況下,使用期可能會超過其過時時間
Cache-Control: no-cache 除非資源進行了再驗證,不然這個客戶端不會接受已緩存的資源
Cache-Control: no-store 緩存應該儘快從存儲器中刪除文檔的全部痕跡,由於其中可能會包含敏感信息
Cache-Control: only-if-cached 只有當緩存中有副本存在時,客戶端纔會獲取一份副本

注意:文檔過時系統並非一個完美的系統。若是發佈者不當心分配了一個好久以後的過時日期,在文檔過時以前,她要對文檔作的任何修改都不必定能顯示在全部緩存中。所以,不少發佈者都不會使用很長的過時日期。並且,不少發佈者甚至都不使用過時日期,這樣緩存就很難肯定文檔會在多長時間內保持新鮮了。

相關文章
相關標籤/搜索