1 概念 · 穩定性——同一個應用中,對同一數據、邏輯功能和用戶界面的多次請求時經常發生的。當用戶基數很大時,如果每次請求都進行處理,消耗的資源是很大的浪費,也同時造成系統的不穩定。例如,web應用中,對一些靜態頁面的呈現內容進行緩存能有效的節省資源,提高穩定性。而緩存數據也能降低對數據庫的訪問次數,降低數據庫的負擔和提高數據庫的服務能力; · 可用性——有時,提供數據信息的服務可能會意外停止,如果使用了緩存技術,可以在一定時間內仍正常提供對最終用戶的支持,提高了系統的可用性。 1.2 理解狀態 1.2.1 狀態的生存期 ·永久狀態Permanent State——應用程序使用的永久數據; ·進程狀態Process State——只在進程週期內有效; ·會話狀態Session State——和特定的用戶會話有關; ·消息狀態Message State——處理某個消息的時間內有效; 1.2.2 狀態的範圍 ·物理範圍指可以被訪問到的狀態數據存放的物理位置,通常包括: 1、 組織Organization——在一個組織內的所有應用程序可以訪問狀態數據; 2、 場Farm——在應用場範圍內的任何機器上都可以訪問; 3、 機器Machine——單個機器範圍內可以訪問; 4、 進程Process——進程內的訪問許可; 5、 應用域AppDomain——應用程序域內的訪問許可。 ·邏輯範圍指可訪問狀態數據的邏輯範圍,常見的有: 1、 應用程序Application; 2、 業務流程Business Process; 3、 角色Role; 4、 用戶User; 1.2.3 狀態數據的陳舊 ·主數據更改的可能性——隨着時間的推進,主數據更改的可能是否大大增加?安照這一點來決定緩存狀態數據的陳舊; ·更改的相關性——主數據更新時,緩存的狀態數據不相應更新是不是造成影響系統的使用?比如,更改系統的外觀風格並不會對業務造成很大影響。 1.2.4 狀態數據陳舊的容忍度 1.2.5 理解狀態數據的轉換過程 表現形式 當決定緩存數據時,應該考慮緩存哪個階段(哪種形式)的狀態數據。以下方針有助於你做決定: · 當業務邏輯可以容忍緩存數據的陳舊時就緩存原始數據;原始數據可以緩存在數據庫訪問組件和服務代理中; ·緩存處理過的數據以減少處理時間和資源;處理過的數據可以緩存在業務邏輯組件和服務接口中。 ·當需要呈現的數據量很大並且控件的呈現時間很長時,緩存呈現數據(比如包含大數據量的Treeview控件)。這種數據應該被緩存在UI控件中。 1.3 爲什麼要緩存數據 ·減少交互的通訊量——緩存數據能有效減少在進程和機器間的傳輸量; ·降低系統中的處理量——減少處理次數; ·降低需要做的磁盤訪問次數——比如緩存在內存中的數據。 1.4 數據應該被緩存在哪裏 1、 存儲類型Storage Type——數據可用的物理存儲位置; 2、 層間的架構元素(Layered architecture elements)——數據可用的邏輯存儲位置。 1.4.1 存儲類型 1、 內存駐留緩存——包含在內存中臨時存儲數據的所有實現方法,通常在以下情況下使用: a) 應用程序頻繁使用同樣的數據; b) 應用程序需要經常獲取數據; 通過將數據保留在內存中,你可以有效降低昂貴的磁盤訪問操作,也可以通過將數據保留在使用者進程中來最大程度的減少跨進程的數據傳輸。 2、 磁盤駐留緩存——這種技術包含所有使用磁盤作爲存儲介質的緩存技術,如文件和數據庫。在以下情況下基於磁盤的緩存是很有效的: a) 處理大數據量時; b) 應用服務提供的數據可能並不是總能使用(比如離線的情況); c) 緩存的數據必須能在進程回收和機器重啓的情況下保持有效; 通過緩存處理過的數據,你可以有效降低數據處理的負擔,同時可減少數據交互的代價。 1.4.2 架構間元素 當使用這些組件進行工作時,你需要考慮哪些數據可以被緩存起來,還有以哪種方式進行緩存會對程序的整體性能和可用性有幫助,以上的這些元素都可以緩存相應的數據。當然,要考慮的遠不止這些。 1.5 實施緩存時的考慮 1.5.1 格式和訪問模式 1、 線程安全——當緩存的內容可以被多個線程訪問時,使用某種鎖定機制來保證數據不會被兩個線程同時操作; 2、 序列化——將一個對象緩存時,需要將它序列化以便保存,所以包緩存的對象必須支持序列化; 3、 規格化緩存數據——緩存數據時,相對於要使用的數據格式而言,要保證數據的格式是優化過的。 1.5.2 內容加載 ·提前加載Proactive Load——使用這種方式時,你提前將所有的狀態數據加載到緩存中,可能在應用程序或線程啓動時進行,然後在應用程序或線程的生存期內一直緩存; ·動態加載Reactive Load——或稱反應式加載,當使用這種方法時,在應用程序請求數據時取到數據,並且將它緩存起來以備後續使用。 1.5.3 過期策略 1.5.4 安全性 1.5.5 管理 1.6 小結 2 緩存技術 使用Asp.Net緩存; 使用Remoting Singleton緩存; 使用內存映射文件; 使用SQL Server緩存; 使用靜態變量緩存; 使用Asp.net 會話狀態(Session State); 使用Asp.net客戶端緩存和狀態; 使用Internet Explorer緩存。 2.1 Asp.net緩存 在Asp.net中,提供了專門用於緩存數據的Cache對象,它的應用範圍是應用程序域。生存期是和應用程序緊密相關的,每當應用程序啓動的時候就重新創建Cache對象。它域Application對象的主要區別就是提供了專門用於緩存管理的特性,比如依賴和過期策略。 你可以使用Cache對象和它的屬性來實現高級的緩存功能,同時可以利用Asp.net Cache來對客戶端輸出的響應內容進行緩存。關於Asp.net中的緩存技術,有以下內容要介紹: 2.1.1 編程緩存Programmatic Caching 2.1.1.1 依賴和過期策略 ·文件依賴(File Dependency)——當硬盤上的某個(某些)文件更改時,強制移除緩存數據;如: CacheDependency cDependency = new CacheDependency(Server.MapPath("authors.xml")); Cache.Insert("CachedItem", item, cDependency); ·鍵值依賴(Key Dependency)——指定緩存中的某個數據項更改時移除。如: // Create a cache entry. Cache["key1"] = "Value 1"; // Make key2 dependent on key1. String[] dependencyKey = new String[1]; dependencyKey[0] = "key1"; CacheDependency dependency = new CacheDependency(null, dependencyKey); Cache.Insert("key2", "Value 2", dependency); ·基於時間的過期策略——按照預先定義的時間策略來使數據失效,可以是絕對時間(如某個日期的18:00)也可以是相對現在的相對時間。如: /// Absolute expiration Cache.Insert("CachedItem", item, null, DateTime.Now.AddSeconds(5),Cache.NoSlidingExpiration); /// Sliding expiration Cache.Insert("CachedItem", item, null, Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(5)); 使用太短和太長的過期時間都不行,不是造成用不上的緩存數據,就是緩存了陳舊的數據並加重了緩存負擔,所以可以使用高併發的測試來決定過期時間的最佳值。 ·另外有個問題就是如何實現對數據庫的依賴,這就要求實現自己的通知機制,當數據庫數據改變時能夠通知你的緩存數據改變。可參考http://www.gotdotnet.com/team/rhoward的示例。 由於數據會過期,所以當使用緩存中的數據時,必須檢查數據的有效性。如以下代碼: string data = (string)Cache["MyItem"]; if (data == null) { data = GetData(); Cache.Insert("MyItem", data); } DoSomeThingWithData(data); 依賴和過期策略指定了緩存中數據的移除方式,有時候你可能需要在移除發生時做一些工作,這能靠寫代碼來實現這一點,這就是我們要講到的。 2.1.1.2 使用緩存回調(Cache Callback) CacheItemRemovedCallback onRemove = new CacheItemRemovedCallback(this.RemovedCallback); Cache.Insert("CachedItem", item, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Default, onRemove); // Implement the function to handle the expiration of the cache. public void RemovedCallback(string key, object value, CacheItemRemovedReason r) { // Test whether the item is expired, and reinsert it into the cache. if (r == CacheItemRemovedReason.Expired) { // Reinsert it into the cache again. CacheItemRemovedCallback onRemove = null; onRemove = new CacheItemRemovedCallback(this.RemovedCallback); Cache.Insert(key, value, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Default, onRemove); } } 2.1.1.3 對緩存項使用優先級 Cache.Insert("DSN", connectionString, null, d, t, CacheItemPriority.High, onRemove); 2.1.1.4 刷新數據(清除緩存) Response.Cache.SetExpires(DateTime.Now) 這可以清除緩存,但頁面上並不立刻體現出來,直到最初的緩存期結束,比如: <%@ OutputCache Duration="10" VaryByParam="none" %>指令指定的緩存只會在10秒後才清除。通常並不需要清除所有緩存項,你只要重新加載數據更新緩存就夠了。 2.1.2 輸出緩存(Output Cache) 2.1.2.1 頁面輸出緩存 1、 決定緩存的內容 頁面輸出緩存可緩存各種信息,緩存這些信息意味着你不需要經常處理同樣的數據和結果,包括: ·經常被請求但不不改變的靜態頁面; ·更新頻率和時間已知的頁面(如顯示股票價格的頁面); ·根據HTTP參數,有幾個可能輸出的頁面(如根據城市的代號顯示該城市天氣情況的頁面); ·從Web Service返回的結果;如: [WebMethod(CacheDuration=60)] public string HelloWorld() { return "Hello World"; } 2、 緩存動態頁面 基於輸入參數、語言和瀏覽器類型改變的動態網頁經常用到。你可以使用OutputCache的以下屬性來實現對動態頁面的緩存: VaryByParam——基於輸入參數不同緩存同一頁面的多個版本; VaryByHeader——基於Page Header的內容不同緩存頁面的多個版本; VaryByCustom——通過聲明屬性和重載GetVaryByCustomString方法來定製緩存處理頁面的多個版本; VaryByControl——基於控件中asp對象屬性的不同來緩存控件。 對多個版本頁面的緩存會降低可用內存,所以要仔細衡量緩存策略。s 3、 控制緩存的位置 你可以使用@OutputCache指令的OutputCacheLocation屬性的枚舉值來指定緩存的位置,如: <%@ outputcache duration="10" varybyparam="none" Location="Server" %> 4、 配置頁面輸出緩存 有兩種方式控制,你可以使用Page指令,也可以使用Cache API編程實現。參考以下兩段代碼: //代碼1,使用指令 <%@ OutputCache Duration="20" Location="Server" VaryByParam="state" VaryByCustom="minorversion" VaryByHeader="Accept-Language"%> //代碼2,編程實現 private void Page_Load(object sender, System.EventArgs e) { // Enable page output caching. Response.Cache.SetCacheability(HttpCacheability.Server); // Set the Duration parameter to 20 seconds. Response.Cache.SetExpires(System.DateTime.Now.AddSeconds(20)); // Set the Header parameter. Response.Cache.VaryByHeaders["Accept-Language"] = true; // Set the cached parameter to 'state'. Response.Cache.VaryByParams["state"] = true; // Set the custom parameter to 'minorversion'. Response.Cache.SetVaryByCustom("minorversion"); … } 2.1.2.2 頁面片斷緩存 ·創建開銷很大的頁面片斷(控件); ·包含靜態數據的頁面片斷; ·可被多個用戶使用的頁面片斷; ·多個頁面共享的頁面片斷(如公用菜單條) 以下是緩存部分頁面的例子: // Partial caching for 120 seconds [System.Web.UI.PartialCaching(120)] public class WebUserControl : System.Web.UI.UserControl { // Your Web control code } 2.1.3 在非Web項目中使用Asp.net緩存 System.Web.Caching.Cache 類是對象的緩存,它可以通過System.Web.HttpRuntime.Cache 的靜態屬性或System.Web.UI.Page 和System.Web.HttpContext.Cache來訪問。因此在請求上下文之外也可以存在,在每個應用程序域中只有一個實例,所以HttpRuntime.Cache對象可以在Aspnet_wp.exe之外的每個應用程序域中存在。以下代碼演示了在普通應用裏訪問Cache對象: HttpRuntime httpRT = new HttpRuntime(); Cache cache = HttpRuntime.Cache;
2.2 使用Remoting Singleton緩存 爲了使用.Net Remoting實現緩存方案,要保證遠程對象的租約不過期,並且遠程對象沒有被垃圾回收器銷燬(對象租約是指在系統刪除該對象前它在內存中的生存期)。當實現緩存時,重載MarshalByRefObject的InitializeLifetimeService方法並且返回null,這樣就能保證租約永遠不過期並且相關的對象生存期是無限的。以下代碼是一個示例: public class DatasetStore : MarshalByRefObject { // A hash table-based data store private Hashtable htStore = new Hashtable(); //Returns a null lifetime manager so that GC won't collect the object public override object InitializeLifetimeService() { return null; } // Your custom cache interface } 注意:由於這種方案的成本較高、性能上的限制並且可能造成系統不穩定,通常採用基於Sql Server的方案來替代。 2.3 使用內存映射文件(Memory-Mapped File) 在windows中,代碼和數據是以以種方式處理的,表現形式都是內存頁,而在內存頁背後都是磁盤上的文件。唯一的不同磁盤上的文件類型不同。代碼後面是可執行的鏡像,而數據後面則是系統的頁面文件。當多個應用程序共享內存時,系統的性能會有明顯提升。 你可以使用內存映射文件的這種特性來實現同一臺機器上的跨進程和跨應用程序域的緩存解決方案。基於內存映射文件的緩存方案包含以下組件: ·windows NT服務——啓動時創建內存映射文件,停止時刪除它。功能是向使用緩存的進程提供句柄。當然,也可以使用命名的內存映射文件來提供操作接口; ·緩存託管組件(Cache Management Dll)——實現特定的緩存功能,比如: a. 插入和刪除數據項到緩存中; b. 使用算法清除緩存,比如最後使用算法(Least Recently Used); c. 保證數據不被篡改; 基於內存映射文件的緩存方案可以用在應用程序的每個層中,但由於使用win32 API調用,所以並不容易實現。.Net 框架不支持內存映射文件,所以只能以非託管代碼的方式運行,當然也不能利用.Net框架的有力特性,比如垃圾回收等。同時緩存數據項的管理功能需要定製開發,還要開發性能計數器來監控緩存的效果。 2.4 使用SQL Server緩存 SQL Server在使用sql語句或存儲過程得到數據時,對varchar和varBinary類型的數據有8k的大小限制,你必須使用.Net 框架提供的Ado.Net SQLDataAdapter對象來訪問datatable或dataset。 使用SQL Server緩存數據的優點: ·易於實現——使用.Net 框架和Ado.Net訪問數據庫相當方便; ·完善的安全模型和很高的健壯性; ·數據非常方便的共享; ·數據的持久保留。 ·支持很大的數據量。 ·方便的管理工具 當然,也有缺點: ·需要安裝SQL Server,對小型應用來說不合適; ·重新構造數據的性能和讀取數據庫的性能比較; ·網絡負擔。 2.5 使用靜態變量緩存 你可以使用這種方案保存大數據的對象,前提是它不經常更改。由於沒有清除機制,大數據的內存消耗會影響性能。 你需要保證定製線程安全機制,或者使用.Net框架提供的同步對象,比如Hashtable。以下代碼是使用Hashtable實現的例子: static Hashtable mCacheData = new Hashtable(); 應用範圍:本方案的應用範圍可以限制到類、模塊或整個項目。如果變量定義爲public,整個項目中的代碼都能訪問它,範圍是整個應用程序域,實現了高效的共享。而它的生存期是和範圍緊密相關的。 2.6 使用asp.net session state ·asp session要求客戶端接受cookies,否則就不能使用session;而asp.net可以配置爲不使用cookie; ·對web server場的情況,asp的session不能支持;當穩定性和可用性要求很高時,asp.net session state雖然效果不好,但對比較小的單個值scalar Value(比如登錄信息),還是很有效。 Asp.net session有很大改進,下面描述使用範圍和使用方式。 Asp.net session state有三種操作模式: 1、 進程內模式InProc——Session State信息在asp.net工作進程aspnet_wp.exe的進程的內存中存儲。這是默認選項,這種情況下,如果進程或應用程序域被回收,則Session 狀態信息也被回收; 2、 進程外模式State Server——狀態信息序列化後保存在獨立的狀態進程中(AspNet_State.exe),所以狀態信息可以保存在專門的服務器上(一個狀態服務器State Server); 3、 Sql server模式——狀態信息序列化後保存在SQL Server數據庫中。 你可以通過調整配置文件中<sessionState>標籤的mode屬性來設置要使用的狀態模式,比如使用SQL Server模式來在Web server場中共享狀態信息。當然,這個優勢也有缺點,就是狀態信息需要序列化和反序列化,同時多了對數據庫的寫入和讀取,所以性能上有開銷,這是要仔細評估的。 2.6.1 選擇使用模式 進程內模式是唯一支持Session_End事件的session模式,當用戶會話超時或中止時,可以運行Session_End中的事件處理代碼來清除資源。 2.6.1.2 使用StateServer模式 當使用Session對象在web場的情況下使用時,必須保證web.config文件中的<MachineKey>元素在所有服務器上是唯一的。這樣所有的服務器使用同樣的加密方式,才能訪問緩存中的數據。參考msdn中的“MachineKey元素”。 2.6.1.3 使用SQL Server模式 默認情況下,SQL Server將狀態信息存儲在TempDb數據庫中,它在每次Sql server服務啓動時會自動重新創建,當然,你可以指定自己的數據庫以便在數據庫重啓的過程中也能保持數據。 2.6.2 決定使用Session對象要存儲的內容 1、 對基本類型(比如Int,Byte,String)來說,可以使用任何方式。因爲在選用進程外方式時,asp.net使用一個優化的內部方法來序列化和反序列化基本類型的數據; 2、 對複雜類型(如ArrayList)來說,只選用進程內方式。因爲asp.net使用BinaryFormatter來序列化和反序列化這類數據,而這會影響性能的。當然,只有在State Server和SQL Server的方式下,纔會進行序列化操作; 3、 緩存的安全問題,當在緩存中存儲敏感數據時,需要考慮安全性,其它頁面可以訪問到緩存中的數據; 4、 避免緩存大數據,那會降低性能; 5、 這種緩存方式不支持過期策略、清除和依賴。 2.6.3 實現Session State 以下代碼演示了使用SQL Server來實現Session數據的存儲和使用。 <sessionState mode="SQLServer" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1; Integrated Security=SSPI" cookieless="false" timeout="20" /> private void SaveSession(string CartID) { Session["ShoppingCartID"] = CartID; } private void CheckOut() { string CartID = (string)Session["ShoppingCartID"]; if(CartID != null) { // Transfer execution to payment page. Server.Transfer("Payment.aspx"); } else { // Display error message. } } 2.7 使用Asp.net客戶端緩存和狀態 實現客戶端緩存的機制有以下五種,接下來將依次介紹: ·隱藏欄位(Hidden Field) ·View State ·隱藏幀(Hidden Frame) ·Cookies ·Query String 這五種方式分別適合於存儲不同類型的數據。 2.7.1 使用Hidden Field 使用這種方式的優點如下: 不需要服務器資源,直接從頁面中讀取; 由於可以通過查看源碼看到,所以可能會被篡改; <input id="HiddenValue" type="hidden" value="Initial Value" runat="server" NAME="HiddenValue"> 2.7.2 使用View State 使用View State的性能表現很大程度上依賴於服務器控件的類型。一般來說,Label,TextBox,CheckBox,RadioButton,HyperLink的性能要好一些,而DropdownList,ListBox,DataGrid和DataList就要差很多,因爲包含的數據量太大,所以每次頁面回送都很耗時間。 有些情況下不推薦使用ViewState,比如: 1、 不需要回送的頁面避免使用; 2、 避免使用ViewState保存大數據量; 3、 在需要使用會話超時的情況下避免使用它,因爲它沒有超時操作。 ViewState的性能表現和Hidden Field的是類似的,但是具有更高的安全性。 優點: 數據在頁面中自動維護,不需要服務器資源; 存儲大數據量時會降低性能; public class ViewStateSample : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { if (!Page.IsPostBack) { // Save some data in the ViewState property. this.ViewState["EnterTime"] = DateTime.Now.ToString(); this.ViewState["UserName"] = "John Smith"; this.ViewState["Country"] = "USA"; } } … private void btnRefresh_Click(object sender, System.EventArgs e) { // Get the saved data in the view state and display it. this.lblTime.Text = this.ViewState["EnterTime"].ToString(); this.lblUserName.Text = this.ViewState["UserName"].ToString(); this.lblCountry.Text = this.ViewState["Country"].ToString(); } } 2.7.3 使用Hidden Frame 優點: a. 可以加載較多數據而不只是單個欄位的值; b. 避免了不必要的多次回送中的數據往來; c. 可以緩存和讀取在不同表單中存儲的數據項(可以同時緩存多個頁面的數據); d. 可以訪問同一站點不同frame中的客戶端腳本數據。 缺點: a. 有些瀏覽器不支持frame; b. 源代碼可以在客戶端看到,有潛在的安全威脅; c. 隱藏frame的數量沒有限制,如果框架頁面包含較多hidden frame的話,在首次加載時速度會有限制。 示例代碼如下: <FRAMESET cols="100%,*"> <FRAMESET rows="100%,*"> <FRAME src="contents_of_frame1.html"> </FRAMESET> <FRAME src="contents_of_hidden_frame.html"> <FRAME src="contents_of_hidden_frame.html" frameborder="0" noresize scrolling="yes"> <NOFRAMES> <P>This frameset document contains: <A href="contents_of_frame1.html" TARGET="_top">Some neat contents</A> </NOFRAMES> </FRAMESET> 2.7.4 使用Cookies 優點: 不需要服務器資源;數據保存在客戶端,在用戶請求時發送到服務器上。 數據量的限制; public class CookiesSample : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { if (this.Request.Cookies["preferences1"] == null) { HttpCookie cookie = new HttpCookie("preferences1"); cookie.Values.Add("ForeColor","black"); cookie.Values.Add("BackColor","beige"); cookie.Values.Add("FontSize","8pt"); cookie.Values.Add("FontName","Verdana"); this.Response.AppendCookie(cookie); } } private string getStyle(string key) { string val = null; HttpCookie cookie= this.Request.Cookies["preferences1"]; if (cookie != null) { val = cookie.Values[key]; } return val; } } 2.7.5 使用Query String 優點: d. 不需要服務器資源,參數附在URL裏面; e. 應用面廣,幾乎所有瀏覽器都支持; f. 實現簡單,服務端使用Request對象可直接讀取。 缺點: a. 參數直接對用戶可見,不安全; b. URL長度的限制,多數瀏覽器不支持超過255字符的URL。 示例代碼: http://www.cache.com/login.asp?user=ronen string user = Request.QueryString["User"]; 2.7.6 小結 緩存機制
2.8 使用Internet Explorer緩存 適合在Internet Explorer中緩存的內容 頁面中的圖像文件; 減少對服務器的請求和網絡負擔; 客戶端的過期時間必須預先指定而不能依賴於服務器更新;IE採用的是Lazy更新機制,優先從緩存中提取數據; <META HTTP-EQUIV="expires" CONTENT="Tue, 23 Jun 2002 01:46:05 GMT"> 3 總結
|
緩存技術探討
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.