細說Cache

 

什麼是緩存?

Web 應用程序通常都是被多個用戶訪問。一個Web站點可能存在一個“重量級”的加載,它能夠使得站點在訪問的時候,拖慢整個服務器。當站點被大量用戶同時訪問的時候,訪問速度緩慢是大部分網站共同存在的問題。爲了解決這個問題,我們可以使用一個更高級別的硬件配置,負載均衡器,高帶寬,但是加載並不是拖慢站點唯一的“罪魁禍首”,所以我們需要提供一種方案,它也同樣能夠加速數據訪問以及提升性能。而採用緩存正是一種很不錯的解決方案。

緩存是一種能夠存儲我們通常需要使用的數據的技術,它能夠把web 頁面暫時存儲在本地的硬盤上以供後續的檢索。這種技術在多個用戶同時訪問一個站點,或者一個用戶多次訪問一個站點時,有效地提升了訪問速度。爲Web應用程序做的緩存可以發生在客戶端(瀏覽器緩存),可以作用在客戶端和服務端之間的一個服務器上(代理緩存/反向代理緩存),或者只作用在web服務器本身(頁面緩存或數據緩存)。

我們可以選擇花費大量的時間來存儲緩存數據以提升應用程序的性能,但這並沒有真正意義上達到我們的目的。因爲如果我們考慮到Web 服務器的負載,我們就不得不考慮緩存數據存儲的位置。接下來一節我們來討論緩存的不同位置。

緩存所在的不同位置

一個web應用程序的緩存要麼處於客戶端(客戶端瀏覽器),在客戶端與服務器之間(代理或反向代理緩存),要麼處於服務端(數據緩存、頁面輸出緩存)。所以我們就能夠區分出緩存的位置:

    1、  客戶端緩存

2、  代理緩存

3、  反向代理緩存

4、  Web服務器端緩存

1、  客戶端緩存

在採用客戶端緩存時,客戶端瀏覽器通過在本地硬盤上存儲緩存的數據作爲一個零時文件,或者存儲在瀏覽器的內部存儲器上來執行緩存操作。它提供了一種快速訪問相同數據的方式,因爲它拒絕任何的網絡加載以及服務端加載。該數據不能夠被其他客戶端共享,所以是客戶端獨有的。


優勢

1、  因爲數據存儲在本地客戶端,所以可以很容易地訪問

2、  避免了網絡傳輸

劣勢

1、  緩存的數據獨立於瀏覽器,所以是無法被共享的

2、 代理緩存

客戶端緩存的主要的劣勢是數據存儲在客戶端瀏覽器,屬於客戶端私有的。而代理緩存使用一種獨有的服務器在服務端與客戶端之間以一種共享的“位置”來緩存數據,所以所有的客戶端都可以使用相同的共享數據。代理服務器(例如微軟的代理服務器)來滿足所有對web頁面的請求,而無需將請求跨越網絡傳輸到最終的web服務器,這能夠使得快速訪問成爲現實。


代理緩存通常位於網絡的網關附近來減少帶寬的使用。有時通過多代理緩存服務器的使用來緩解大量用戶訪問代理的壓力。這被稱之爲一種緩存集羣。


優勢

1、  數據被緩存在代理服務器可以很容易就被訪問

2、  減少網絡通信

劣勢

1、  涉及到部署以及爲了維護代理緩存服務器的基礎設施的開銷

3、反向代理緩存

 有些代理緩存服務器可以被防止到web 服務器的前端來減少他們接受到的請求的數量。它允許代理服務器處理通常接受到的請求,而僅僅傳遞其他的“特殊”請求給服務器。這稱之爲反向代理。


優勢

1、  被緩存在反向代理服務器上的數據可以很容易地獲得

2、  減少請求的數目

劣勢

1、  當該服務器被配置在web服務器的前端,它可能導致額外的網絡通信

4、web服務器緩存

在web服務端做緩存,緩存的數據被存儲在web服務器上。數據緩存以及頁面緩存可以使用web服務器這種緩存方案。


優勢

1、  提高站點的性能,減少了從數據庫以及其他服務器檢索數據的開銷。

劣勢

1、  增加了網絡加載開銷

緩存的優勢

1、  減少服務端的負載

2、  減少了帶寬的消耗

ASP.NET中的緩存

Asp.net提供對頁面、部分頁面(頁面片段),以及數據的緩存。緩存一個動態生成的頁面被稱之爲頁面輸出緩存。當一個動態生成的頁面被緩存,它只是第一次被訪問。任何後續對相同頁面的請求都將從緩存返回。Asp.net也提供緩存頁面部分的緩存方式,被稱之爲部分頁面緩存或者頁面片段緩存。當採用數據緩存時被緩存的服務端數據(例如來自數據庫的數據、XML數據)能夠被簡單地訪問,而無需做再次檢索。緩存減少了從數據庫或其他數據源獲取數據的開銷。Asp.net提供一種“全套的”數據緩存引擎,包括清除(基於緩存的優先級),過期,文件,鍵,以及時間依賴。在asp.net中,有兩種緩存形式可以提升性能。


在上面的圖片中,(1)用來返回頁面的緩存,這意味着它是用於輸出緩存的,而(2)使用數據緩存,通過存儲數據來減少獲取數據的開銷。

Asp.net支持兩種形式的過期策略,這決定了什麼時候對象將失效或者被從緩存中移除。

絕對過期:絕對過期發生在一個標識的時間。絕對過期時間被標識爲一種全日期格式(hh:mm:ss)。在標識的時間,對象將從緩存中過期。

Asp.net 支持三種類型的緩存:

1、  頁面輸出緩存【輸出緩存】

2、  頁面片段緩存【輸出緩存】

3、  數據緩存

 

不同類型的緩存

1、  頁面輸出緩存:在開始頁面輸出緩存之前,我們需要知道生成一個頁面的過程,因爲基於生成的頁面,我們應該能夠理解爲什麼我們應該使用緩存。一個aspx頁面經過兩個階段的處理後被完成。首先,代碼被編譯進MSIL。然後,在執行期間,MSIL被編譯到本地代碼(通過JIT,即‘即時編譯器’)。當我們編譯站點的時候,一個asp.net頁面的整個代碼都被編譯如MSIL,但是在執行的時候,僅僅只有部分MSIL被轉換爲本地代碼,這提升了性能。


現在,不管我們得到了什麼,如果有某個頁面不是經常的變化,JIT就不需要每次都編譯它。我們可以爲那些內容相對靜態的頁面使用輸出緩存。而不是對每個用戶的請求,都去生成一個頁面,我們可以使用頁面輸出緩存,以使得它可以從緩存中訪問其自身。頁面只需要被生成一次,然後的請求都從緩存中獲取。頁面輸出緩存允許一個頁面的整個內容都存儲在緩存中。

在這幅圖中,當第一次請求生成完頁面,頁面被緩存,而對之後的相同頁面的請求,該頁面會被從緩存中檢索出,而不是再次生成。

對輸出緩存,一個OutputCache屬性可以被直接添加到任何一個asp.net頁面,指定一個該頁面被緩存的持續時間(秒)

示例

  1. <%@ Page Language="C#" %>  
  2. <%@ OutputCache Duration='300' VaryByParam='none' %>  
  3. <html>  
  4.   
  5.   <script runat="server">  
  6.     protected void Page_Load(Object sender, EventArgs e) {  
  7.         lbl_msg.Text = DateTime.Now.ToString();  
  8.     }  
  9.   </script>  
  10.   
  11.   <body>  
  12.     <h3>Output Cache example</h3>  
  13.     <p>Page generated on:  
  14.        <asp:label id="lbl_msg" runat="server"/></p>  
  15.   </body>  
  16. </html>  

我們也可以在後臺代碼裏設置緩存屬性

  1. void Page_Load(Object sender, EventArgs e) {  
  2.       Response.Cache.SetExpires(DateTime.Now.AddSeconds(360));  
  3.       Response.Cache.SetCacheability(  
  4.                    HttpCacheability.Public);  
  5.       Response.Cache.SetSlidingExpiration(true);  
  6.       _msg.Text = DateTime.Now.ToString();  
  7. }  

我們不得不提及duration以及VaryByParam屬性。Duration定義緩存將會持續多長時間。VaryByParam定義不同的緩存參數值


就像上面展示的這幅圖一樣,如果我們對一個頁面使用一個查詢字符串,我們需要基於該參數緩存所有的頁面,我們可以使用VaryByParam屬性。基於查詢字符串,數據應該被緩存,當用戶請求一個頁面,並攜帶一個查詢字符串(圖片中是ID),頁面也能夠在緩存中被檢索到。下面的例子描述了VaryByParam屬性的使用。

示例:

  1. <%@ OutputCache Duration="60" VaryByParam="*" %>  
  2. <! page would cached  for 60 seconds, and would create a separate cache  
  3.    entry for every variation of querystring -->  

下面這幅圖展示了最通用也是最重要的輸出緩存的屬性:


我們制定的所有outputCahce的屬性,都來自System.Web.HttpCachePolicy類的實例。由asp.net提供的緩存策略的完整實現都封裝在HttpCachePolicy類中。

輸出緩存位置

就像我剛纔提到的,我們可以存儲緩存數據在不同的地方——客戶端,服務器,代理服務器。現在,我將怎麼設置緩存數據的位置。如果我們存儲緩存數據,它將從緩存中檢索出頁面從而節省了頁面的生成時間。但是另一種方式是可以保存數據在客戶端瀏覽器,它可以減少網絡通信。而OutputCache執行能夠使用所有的三種方式的緩存——服務器,客戶端,代理(默認)。

接下來的飆歌展示了緩存位置的明細。它展示了緩存處在的位置,以及對Cache-Control和過期時間頭的影響。


例如,如果你爲Location屬性設置Client值,頁面將不會被保存在服務端的緩存中,但是響應中將包含一個Cache-Control響應頭(通過使用Cache-Control頭,頁面可以指明是否他們應該被緩存在一個代理上)設值爲private,並且一個Expires頭(Http 響應,指明該頁面需要重新從服務器請求的日期和時間)值爲一個時間段,它是由Duration屬性指明的。

例子

  1. <%@ OutputCache Duration='120' Location='Client' VaryByParam='none' %>  

該自理將保存緩存120秒,緩存的數據不會保存在服務端,而應該在客戶端瀏覽器。

2、頁面片段緩存:asp.net提供一種對頁面片段的緩存方案,稱之爲頁面片段緩存。爲了緩存一個頁面的一部分,你必須首先將這“部分頁面”封裝到一個用戶控件中。在用戶控件的源文件中,加入一個outputcache指令,並指明Duration以及VaryByParam屬性。當用戶控件在運行時被家載入一個頁面中,它將會被緩存,並且所有的引用了相同用戶控件的其他頁面也將能夠從緩存中檢索數據。


接下來的示例顯示了緩存片段的一些細節:

示例

  1. <!— UserControl.ascx —>  
  2.   
  3. <%@ OutputCache Duration='60'  
  4.                 VaryByParam='none' %>  
  5. <%@ Control Language="'C#'" %>  
  6.   
  7. <script runat="server">  
  8.   protected void Page_Load(Object src, EventArgs e)  
  9.   {  
  10.      _date.Text = "User control generated at " +  
  11.                    DateTime.Now.ToString();  
  12.   }  
  13. </script>  
  14. <asp:Label id='_date' runat="'server'" />  

這裏我已經緩存了一個用戶控件,所以無論何時我們再一個頁面中使用它,該頁面的這部分都將會緩存起來。

3、數據緩存:數據緩存能夠動態地提供一個應用程序的性能,因爲它減少了數據檢索所帶來的一切“開銷”。其實很簡單,數據緩存將請求的數據存儲在緩存中,這樣web服務器就不需要對到來的所有請求去請求數據庫服務器,它能夠增加web站點的性能。爲了實現數據緩存,我們需要找到那些可訪問的並且非常普遍的數據。並且數據緩存是也是一種“全套特性”的緩存引擎,能夠使你在多個Http請求以及多個來自相同應用程序裏的會話之間檢索和存儲數據。


上面的圖片展示了數據如何從數據庫中北之間訪問以及數據是如何從緩存中被重新檢索。數據緩存不僅可以緩存SQL Server中的數據,我們甚至能夠存儲如圖1.4中所示的其他數據源。

現在,讓我們看看如何在web應用程序中實現數據緩存。這裏有三種不同的方式來將數據或者對象加入緩存。但是,基於不同的方案,我們有不同的訪問數據的方式。這些方法是Cache[],Cache.add(),cache.insert()。接下來的表格向你清晰地展示了這三種方法的異同點:


Cache[]是一種非常容易使用的屬性,但cache.insert()以及cache.add()給我們對於緩存數據更多的控制。

現在我們需要看看cache.insert()以及Cache.Add()的細節。Cache.Insert()有四個重載方法,而Cache.Add()怎沒有重載方法。接下來的表格展示了這些方法的大部分通用屬性。


開始的兩個是強制被Cache.Insert()方法使用的,而其他幾個則有所不同。

緩存依賴

使用緩存依賴,我們可以爲某些數據或可能改變的實體設置依賴。所以我們能夠通過設置緩存依賴來更新或者移除緩存。在asp.net中支持三種類型的依賴:

(1)      基於文件的依賴

(2)      基於鍵的依賴

(3)      基於時間的依賴

基於文件的依賴:基於文件的依賴,在當磁盤上的文件改變時,可以讓一個通常的緩存項失效。

使用緩存依賴,當文件改變時,我們可以從緩存中強制失效某些緩存項。我們可以設置多個文件依賴。在這樣的情況下,依賴應該被建立在一組文件或文件夾上。

使用:基於文件的依賴是非常有用的,當你需要更新更新的數據是基於某個文件的時候。例如,一個新聞站點總是從一個文件中去獲取數據,但是,如果某些爆炸性的新聞出來,他們只需要更新下文件,然後緩存就該失效,並且在失效時間之內,我們通過OnRemoveCallBack回調可以重新加載緩存中的已被更新的數據。

基於鍵的緩存依賴:基於鍵的依賴,在當另一個緩存項改變時,讓一個通常的緩存項失效。

使用:當我們有多個內部關聯對象在緩存中時,這將會非常有用,我們需要更新或過期所有的這些對象。

基於時間的緩存依賴:基於時間的依賴會讓一個緩存項在預定的時間失效。Cache的Cache.Insert()方法被用來創建一個基於時間的緩存依賴。可以對其設置兩種類型的時間:

(1)      絕對時間

(2)      “滑動”時間(相對的)

絕對:給一個緩存項設置一個失效的絕對時間。它是一個全時間格式,包含(hh:mm:ss)。

滑動:對每個請求重置緩存項的失效時間。當緩存項需要爲了來自多個客戶端的請求都保持存活的時候,它是非常有用的。

對這些所有的依賴,asp.net允許下面的操作發生:

自動失效:那些在使用中並且沒有任何依賴的緩存項都會自動失效。

支持回調:緩存對象能夠被配置來調用一個被“賦予”的一段代碼,當一個緩存項被從緩存中移除時,這些代碼就會被調用。這給了你機會去更新緩存。我們可以使用OnRemoveCallback()。

緩存使用的注意事項

輸出緩存注意事項:

1、  使得一個頁面上的輸出緩存在通常情況下能夠訪問,對所有這些訪問都確保他們返回一致的內容。

2、  當對一個頁面使用輸出緩存時,確保不引入不正確的行爲,不爲特定的用戶做處理。

3、  謹慎地決定緩存頁面的過期時間,平衡訪問速度與內存消耗以及高速緩存一致性的正確訪問(吞吐量)。

4、  如果你使用的是VaryByParam=’*’,考慮使用頁面滑動過期。

數據緩存注意事項:

1、  數據緩存不是一個共享的可更新狀態的容器

2、  緩存的數據是通常需要訪問的以及獲取相對比較“昂貴”的。

3、  如果數據依賴於文件,文件夾,或者其他的緩存實體,使用一種CacheDependency來確保它滿足當前的需求。

緩存類型的建議

場景一:生成的頁面通常都相同,但是有某些展示的表單通常會更新(使用頁面片段緩存

場景二:生成的頁面總是在變化,但是有一些對象並不是經常變動(使用數據緩存

場景三:生成的頁面每隔幾個小時變化一次,當信息通過一種自動處理過程從數據庫中被加載時(使用頁面輸出緩存並且設置過期時間來匹配數據庫的更新時間)。

更多關於緩存使用的注意事項,請參考:開發中常見的十種對緩存的錯誤使用

----部分內容參考自CodeProject,特此註明!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章