Web緩存解決方案

緩存是構建於HTTP統一接口之上的最有用功能之一。能夠利用緩存減小終端用戶感知到的延時,增長可靠性,減小帶寬使用和成本,下降服務器負載。緩存無處不在,能夠在服務器網絡裏,內容分發網絡(Content delivery network,簡稱CDN)或是客戶端網絡裏(一般被稱爲轉發代理Forward Proxy)。數據庫

  1. 如何設置過時緩存頭
    當緩存能夠在不訪問源服務器時作出儘量多的響應時,它是最高效的。設計過時緩存(Expiration Caching)就是爲了下降源服務器收到的請求數量,同時減小應用程序使用的帶寬。過時緩存基於Cache-Control和Expires這兩個頭,它們指導客戶端和緩存在一段指定時間內保存從服務器返回的表述副本。在這個時間窗口之內,甚至超出該時間窗口,緩存能夠對後續請求作出響應,無需訪問源服務器。

    下面是Cache-Control指令列表及其適用性:

    public 默認指令。當請求是通過身份驗證的,但您仍但願共享緩存提供緩存響應時,也可使用該指令。
    private當響應專屬於某個客戶端或用戶時,使用該指令。任意客戶端緩存(如瀏覽器緩存或轉發代理)均可以緩存表述,但諸如服務器緩存或網絡之類的共享緩存則不能進行緩存。在基於客戶端或用戶身份驗證來提供表述的時候添加該指令。
    no-cache和no-store 經過這些指令能夠避免緩存存儲或提供已經緩存的響應。如非必要,通常不使用這些指令。
    max-age該指令的值即爲新鮮壽命,單位爲秒。
    s-maxage這個指令與max-age相似,但只對共享緩存有意義。在源服務器同時設置了max-age和s-maxage時,緩存會使用s-maxage頭。實際上,單獨設置max-age指令就足夠了。
    must-revalidate要求緩存在提供陳舊的表述前先檢查源服務器。
    proxy-revalidate只應用於共享緩存。
    最佳過時緩存的關鍵是爲資源表述計算一個合理的新鮮壽命值。若是有歷史信息,例如表述的更新日誌,能夠參考它們來創建基線壽命。若是沒有此類數據,能夠先從一個合理的推測值出發,在獲取更多信息後對其作出調整。一般這些信息源自於您發現某個客戶端看不到最近更新的表述。
    相似Squid這樣的緩存還支持兩個Cache-Control頭的擴展指令——state-if-error和state-while-revalidate。服務器能夠用stale-if-error來告訴緩存,它們能夠在指定時間間隔內繼續提供陳舊的響應。
  2. 什麼時候設置過時緩存頭
    HTTP規定了什麼是能緩存的,什麼是不能緩存的,緩存也可能只實現了部分HTTP緩存協議。
    爲全部帶成功響應碼的GET和HEAD請求的響應設置過時緩存頭。雖然POST是可緩存的,但緩存會把該方法視爲不可緩存的。其餘方法無需設置過時緩存頭。
    除了帶200(OK)響應碼的成功響應,還能夠考慮緩存待3**和4**響應碼的HTTP頭,這能減小由客戶端錯誤帶來的流量。這種作法被稱爲消極緩存(negative caching)。
     
    300(multiple choices)帶這個狀態碼的表述不太可能常常發送變化,緩存此類應答能夠下降服務器負載。
    301(Moved Permanently)當資源永久移動時,那些將URI存儲在數據庫中的客戶端可能不會修改這些URI。在這種狀況下,緩存能夠不用訪問源服務器,直接提供重定向響應。
    400(Bad Request)當服務器返回該狀態碼時,客戶端按理說不應重複請求,但出於軟件錯誤或惡意攻擊等緣由,有些客戶端會重複發起請求。
    403(Forbidden)若是服務器永久拒絕服務該資源,請爲其添加緩存。
    404(Not Found)該資源不存在,並且不必讓服務器僅爲失敗生成表述。
    405(Method Not Allowed)客戶端可能會由於軟件錯誤而重複發送此類請求。
    410(Gone)資源再也不存在了,因此緩存應該儘量久地提供錯誤響應。
  3. 什麼時候以及如何在客戶端使用過時緩存頭
    除非你是在構建一個封裝在壓縮包內的、須要用戶安裝並運行的客戶端應用程序,不然應該避免在客戶端應用程序中實現對過去緩存的支持。能夠在客戶端網絡中部署一個轉發代理緩存,避免在客戶端代碼中實現本身的緩存層。
    一般狀況下,客戶端應獨立於過時緩存以外。理論上是有可能構建支持HTTP緩存協議的客戶端應用程序的。舉例來講,常見的瀏覽器實現了過時緩存,並將表述存儲在內存或文件系統之中。實際上,在客戶端應用程序中構建並維護一個緩存是項很麻煩的工做。它涉及正確地實現no-store,no-cache和must-revalidate這樣的過時指令,還要遵循Vary頭的內容。在同一個運行時內放入緩存還會形成客戶端應用程序代碼與緩存代碼爭奪內存與CPU資源,這會讓客戶端的調優變得更加困難。
    相較之下,在客戶端和服務器之間放置一個轉發代理緩存更容易一些。不涉及任何開發活動,你就能夠坐享通過精心測試的、健壯的緩存基礎設施所帶來的好處,無須本身構建。這麼作還爲往後擴展留下了空間,你能夠架設一個全部客戶端共享的轉發代理服務器集羣。
    若是客戶端和服務器在同一個網絡裏,不必定須要轉發代理。服務器上能夠部署一個被全部客戶端共享的緩存。但若是客戶端是在和一個其餘網絡中的第三方Web服務交互,那麼使用轉發代理能夠幫助減小客戶端與服務器之間往返請求次數。
  4. 如何支持複合資源的緩存
    基於那些對新舊程度有強烈要求的數據來制定緩存決策,根據它們的變動頻率來設置過時頭。
    相比其它類型資源,複合資源實現緩存更爲複雜,此類資源包含與其餘資源重疊的數據,它們可能會有不一樣的過時時間。
    複合資源是便利性與緩存效率之間權衡的一個好例子。對客戶端而言,複合資源用起來很方便,但服務器要提供最新的資源卻代價很大。
    一個解決辦法是:將複合資源打散成三個資源,但這就強迫客戶端發起屢次請求來獲取數據。換言之,服務器須要考慮利害關係並作出權衡。當資源的表述粒度較粗時,就會發生這種狀況,有可能會以獨立資源的方式來提供表述中所含的數據。
  5. 如何保持新鮮且溫暖的緩存緩存支持的衆多挑戰之一就是保持緩存的「新鮮」(最新狀態)和「溫暖」(非空),就算客戶端沒有發起請求時也是如此。以一個照片分享服務爲例,在用戶上傳照片後,全部針對這些照片的緩存都是空的,所以服務器不得不生成照片的表述。相似的,當引入一個新的緩存時,它是空的,隨着客戶端開始發起請求後,它纔會慢慢有內容。當緩存處於新鮮狀態時,其中包含最新的表述。一個「溫暖」的緩存能避免冷啓動問題。可是,預先保持緩存的新鮮與溫暖不在HTTP範疇以內。儘量地讓過時時間與更新頻率保持同步。當這點很難作到時,實現一些後臺進程來監控數據庫變動,定時執行無條件GET請求來刷新緩存。在定時調度這些請求時,必定要考慮到數據庫複製的延遲。若是正在使用Squid,可使用HTTP緩存頻道擴展(HTTP cache channel extension)向緩存傳播資源更新。在HTTP中,當客戶端提交PUT,POST或DELETE請求時,要求緩存做廢表述。此後,客戶端再對同一資源發起GET或HEAD請求時,緩存就能從源服務器得到一個新的表述。儘管這種作法不過高效(由於緩存沒法保持非空狀態),但它卻保證了客戶端能得到最新的表述。現實中,你的網絡裏可能有多個應用程序會讀寫相同的數據存儲,只要其中任意應用程序的寫操做繞過HTTP緩存和服務器,那麼就會致使緩存的表述變舊。考慮如下場景:服務器上可能會有每晚執行的定時任務,更新摘要數據表以反映日間的工做。這個更新可能直接發生在數據庫層面上,不會有任何HTTP請求。但你可能緩存了這個資源,一旦定時任務執行了,存儲在緩存中的應答就舊了。普遍分佈的數據存儲在一天裏可能會週期性地進行復制。數據的改變不會反映在所有的緩存裏。大型應用程序可能會有一個或多個客戶端或服務是使用自定義協議來更新數據的。只要使用這些服務就能夠在不經過HTTP的狀況下改變數據庫,此時緩存並不知道資源發生了變化。
相關文章
相關標籤/搜索