摘 要: 介紹了ASP.NET中各種緩存技術的應用程序模型,并重點分析了每種應用模型的優缺點及其適用范圍。
關鍵詞: ASP.NET 高速緩存 Cookie 會話狀態 應用程序狀態 視圖狀態
隨著經濟全球化的發展,許多公司面對客戶和市場需求的變化,需要構建足夠強大、靈活、可伸縮的信息系統來支撐迅速增加的大量無規律性的訪問和Web流量。
要開發高性能、可縮放的 Web 應用程序,最好的方法是在首次請求項時將這些項存儲在Web服務器上或請求流中的其他軟件上,從而避免重新創建滿足先前請求的信息,可節省時間和資源。這就要使用數據緩存功能。ASP.NET提供了許多緩存功能。為了知道應用程序應該用哪一種緩存功能,需要了解將要開發的應用程序的結構和每種緩存功能的工作特點及其優缺點。作者在軟件開發過程中,積累了有關這方面的一些經驗,現整理出來供大家參考。
1 緩存數據的分類
在Web應用程序中,由于變量的生命周期受限于網頁,所以,每當.aspx文件被解釋執行后,變量的內容將不復存在。為將變量的內容保存下來,簡單的方法是使用緩存來存儲變量的值。ASP.NET提供了輸出緩存和應用程序數據緩存二種方案,用來創建高性能Web應用程序的緩存類型[2]。
緩存數據按其所在網絡節點位置的不同可以分為三類[1][6]:(1)在客戶端緩存數據。(2)在Web服務器上維護緩存數據。(3)在數據庫中維護緩存數據。它是用數據庫儲存Web應用程序的全局或會話數據的一種方式。
2 各種緩存技術的應用模型
2.1 無狀態方式——不維護緩存狀態
在軟件開發中,并非必須使用緩存來保存數據,完全可以通過Web應用程序的ASP.NET代碼執行查詢并用綁定控件將結果轉換為HTML,從而避免緩存數據,使ASP.NET代碼完全是無狀態的。
(1)優點:由于不需要在ASP.NET代碼中緩存數據,所以應用程序的每位用戶需要的內存是最小的。如果單純從內存使用的角度看,這種方式最具有伸縮性。
(2)缺點:應用程序的性能差。假設應用程序是一個在線目錄,則需要在所有頁上顯示產品目錄列表。如果每次用戶訪問頁時都對數據庫進行查詢以得到產品目錄的列表,則將浪費寶貴的數據庫連接資源,降低系統的性能。
2.2 在客戶端緩存數據
這類方法通常是利用瀏覽器(如Explorer)本身固有的緩存機制來實現的。瀏覽器把一定時間內用戶訪問過的文檔或數據都存儲起來,當用戶重新訪問同樣的信息時就可以從瀏覽器的緩存中取出,而不需要重新建立HTTP連接。但是,由于必須將信息發送到客戶端進行存儲,因此這種方式可以存儲的信息量存在一定的客觀限制。
2.2.1 Cookie
Cookie 用于在客戶端上存儲少量經常更改的信息。許多Web站點用Cookie在客戶端儲存用戶信息,這些信息與請求一起發送到服務器。ASP.NET的Request和Response對象都公開一個Cookies集合,可以用它在服務器和客戶端往返行程之間儲存和獲取信息。
(1)優點:①簡單。Cookie是具有簡單鍵值對的、輕量的、基于文本的結構。②可伸縮性好。不需要任何服務器資源,在客戶端儲存數據使ASP.NET代碼成為無狀態的,這可改進可伸縮性。③可配置到期時間。可以通過設置HttpCookie對象的Expires屬性,控制Cookie的失效時間。
(2)缺點:①儲存量大小受到限制。對于緩存返回許多行的查詢結果并不適用。②與瀏覽器安全設置有關。在瀏覽器的安全設置中,可以選擇允許或拒絕創建Cookie,如果瀏覽器選擇禁止接受任何Cookie,則拒絕用Cookie儲存用戶的數據。③安全性差。由于用戶可以修改在客戶端儲存的Cookie內容,所以不可用來存儲像密碼之類的敏感信息。④持久性。客戶端計算機上Cookie的持久性受到客戶端Cookie到期進程以及用戶干預的制約。
2.2.2 隱藏域
可以在頁上的隱藏域中存儲特定于頁的信息,方法類似于Windows窗體中的隱藏控件。ASP.NET提供HtmlInputHidden控件,該控件提供隱藏域功能。但最好使用同它功能類似的ViewState。
(1)優點:①簡單。②可伸縮性好。無需服務器資源,隱藏域在頁上存儲并讀取。③與瀏覽器安全設置無關。幾乎所有瀏覽器和客戶端設備都支持具有隱藏域的窗體。
(2)缺點:①有限的存儲結構。隱藏域不支持豐富的結構,隱藏域提供在其中放置信息的單值域。②安全性差。如果直接查看頁輸出源,可以看到隱藏域中的信息,這導致潛在的安全性問題。③性能降低。由于隱藏域存儲在頁本身,因此,如果存儲較大的值,則在用戶顯示頁和發送頁時,頁的速度就可能會減慢。
2.2.3 視圖狀態(ViewState)
在System.Web.UI名稱空間的Page類公開了一個ViewState屬性,它包含一個類似于名稱/值對集合的StateBag對象。ASP.NET頁框架將ViewState存儲到一個字符串變量,將它發送到客戶端并作為隱藏變量返回。在回發時,頁框架分析來自隱藏變量的輸入字符串并填充每一控件的ViewState屬性。
(1)優點:①可伸縮性好。②與瀏覽器安全設置無關。ViewState是在頁代碼內結構中的一個隱藏域中維護,所以,不管瀏覽器的安全設置如何,都可以用頁面的ViewState來儲存和獲取數據。③儲存量大。頁面可以在ViewState中保存大項目。④頁和控件狀態自動保持。
(2)缺點:①安全性較低。雖然儲存在ViewState中的數據是散列的、壓縮的并且是為Unicode實現而編碼的,但用戶仍然可以解密儲存在頁面上的值。②性能降低。如果存儲較大的值,在用戶顯示頁和發送頁時,頁的速度就可能會減慢。③儲存數據的數據類型受限制。在ViewState中,只能儲存ASP.NET代碼清楚如何序列化的數據,如字符串和整數這樣的簡單數據類型,但不能儲存一般對象。盡管如此,它仍然支持ISerializable接口的對象,如Dataset對象。
2.3 在Web服務器上維護緩存數據
這類方法是在Web服務器上使用內存作為緩存空間[6]。當服務器響應用戶對某個數據請求后,在內存緩存空間中保留一個副本,下一次如果有相同的訪問請求,就直接將緩存空間中的副本提供給用戶。這可加快服務器的反應能力和增加服務器的吞吐量。服務器端的緩存機制能夠減小用戶的訪問延遲,與客戶端緩存相比具有更高的安全性。但可能使用更多的Web服務器資源,增加了服務器硬件和軟件的復雜度,當在信息存儲量較大時限制了應用程序的可擴展性。
ASP.NET提供了在服務器上維護狀態管理的四種方式。
2.3.1 會話狀態(Session)
Page類公開一個Session屬性,可以在Session中存儲會話特定的值和對象,該Session對象將由服務器來進行管理并可用于瀏覽器或客戶端設備。存儲在Session變量中的理想數據是特定于單獨會話的短期的、敏感的數據,直到用戶的會話中止。
對Session的應用,要先通過在文件Global.asax中進行設置,然后在.aspx頁面中進行調用。如可用下面的程序在Global.asax中加上一個Session_Start方法以定義要響應的屬性。
void Session_Start(Object sender,EventArgs e)
{
Session.Add(″lastvalue″,0);
}
賦予屬性一個初值,這樣當在頁面(.aspx)裝入時直接使用這個默認值。對Session值的應用類似于對變量的使用(如Position=(int)Session[″lastvalue″]+1;),如果用它存儲數據集,則必須將其從Object強制轉換回數據集。
(1)優點:①易于實現。Session為ASP開發人員所熟悉,并且與其他.NET框架類一致。②安全性高。數據是由Web服務器而不是在瀏覽器中維護的,用戶不能通過瀏覽器來訪問或修改Session中的內容。③與瀏覽器安全設置無關。Session可用于不支持HTTP Cookie的瀏覽器。④獨立性好。每個用戶的會話設置是分開的,不可共享。⑤會話特定的事件。會話管理事件可以由應用程序引發和使用。⑥持久性。放置于會話狀態變量中的數據在經過Internet信息服務(IIS)重新啟動和輔助進程重新啟動后,會話數據不會丟失。⑦平臺可縮放性。會話狀態對象可在多計算機和多進程配置中使用,因而優化了可縮放性方案。
(2)缺點:①可伸縮性差。應用程序的每個會話都要在服務器上占用一定的資源,當有大量訪問Web應用程序的用戶時,就應考慮要使用的服務器資源總量。②性能降低。Session變量在被移除或替換前保留在內存中,如果其中包含類似大型數據集的信息塊,則可能會因服務器負荷的增加而降低Web服務器的性能。
2.3.2 應用程序狀態(Application)
ASP.NET通過HttpApplicationState類將Application提供為一種存儲全局應用程序特定信息的方法。Application對象與Session對象類似,不同的是通過頁面的Application屬性取得的數據是所有會話所共享的。插入到Application變量的理想數據是那些由多個會話共享并且不經常更改的數據。
(1)優點:①易于實現。②與瀏覽器安全設置無關。③共享性高。因為儲存在Application中的數據對應用程序的所有會話都是可用的,所以它是儲存所有會話都能使用的穩定性數據(如產品目錄列表)的理想位置。
(2)缺點:①可伸縮性差。②持久性。因為在Application中存儲的全局數據是易失的,所以如果包含這些數據的 Web服務器進程被損壞,將丟失這些數據。③全局范圍。在Application中存儲的變量僅對于該應用程序正在其中運行的特定進程而言是全局的,并且每一應用程序進程可能具有不同的值。因此,不能依賴Application來存儲惟一值或更新網絡園和網絡場配置中的全局計數器。④性能降低。當服務器負載增加時,就會降低Web服務器的性能,但比在Session中維護數據的情況要好。
2.3.3 Cache
Page對象公開一個Cache屬性,可以將Cache對象想象為更健壯的Application對象。儲存在Cache中的數據對應用程序的所有會話都是可用的。可以像對Application對象一樣訪問和修改Cache對象的內容[3]。
但在通過Add或者Insert方法向Cache添加項目時,Cache對象還提供了下面的附加功能:
(1)可以通過提供具體值(DateTime)或者相對值(Time-
Span)來指定何時從緩存中刪除該項。
(2)可以指定CacheDependancy,它會在dependent項改變時迫使項從緩存中刪除。
(3)可以指定當項從緩存中被刪除時,ASP.NET要調用的回調函數。
使用Cache對象的優點及缺點與Application對象的很相似,只是Cache對象還提供了額外的緩存刪除功能。
下面給出一個使用Cache存儲大數據的示例。在下面的Web表單中,對第一次請求從數據庫中檢索數據,并把它存入到應用程序緩存。將Dataset加入緩存時,設置5分鐘的到期限制,以便5分鐘內的全部請求都使用緩存的Dataset。對于緩存Dataset到期之后出現的第一次請求,數據庫又會被訪問,新的Dataset開始緩存。為了證實這一觀點,Dataset第一次被創建,就把“鍵—值”對加入到DataSet.ExtendedProperties集合中,這是一個能保存用戶定義的“鍵—值”對集合。用它可存儲Dataset生成時間,這樣就可把它顯示到頁面上。
下面的方法用于在Cache中存儲數據并在控件DataGrid1中顯示。
private void datasetshow( )
{/**構建新的DataSet,并用Cache的Get的方法的結果為它賦值,該方法返回匹配指定鍵名的Object實例,并強制將它轉化為一個DataSet對象*/
DataSet myDataSet=(DataSet) Cache.Get(″CacheddataSet″);
if (myDataSet==null)
{//dataLocationLabel記錄DataSet所在的位置及時間
dataLocationLabel.Text=″<p>第一次來!時間是:″+
DateTime.Now.ToLongTimeString( )+″</p>″;
myDataSet=new DataSet( );
//登錄數據庫服務器并填充數據集
login(″sa″,myDataSet);
//記錄創建時間
myDataSet.ExtendedProperties.Add(″creattime″,
DateTime.Now.ToLongTimeString( ));
//在Cache中插入一個DataSet對象,設置5分鐘到期限制Cache.Insert(″CacheddataSet″,myDataSet,null,DateTime.Now.AddMinutes(5),TimeSpan.Zero);
}
else {
dataLocationLabel.Text=″<p>數據取自cache中,創建時間是:″+myDataSet.ExtendedProperties[″creattime″]+″</p>″+″<p>你這次來的時間是:″+DateTime.Now.ToLongTimeString( )+″</p>″;
}
DataGrid1.DataSource=myDataSet.Tables[″authors″];
DataGrid1.DataBind( );
}
2.3.4 輸出緩存
輸出緩存允許將動態頁或用戶控件響應存儲在輸出流(從發起服務器到請求瀏覽器)中任何具備HTTP 1.1緩存功能的設備上。當后面的請求發生時,不執行頁或用戶控件代碼,緩存的輸出用于滿足該請求。
(1)優點:如果需要根據DataSet的內容重復產生同樣的HTML,則輸出緩存就是最有效的,因為它在服務器端需要的處理更少。與Cache類似,可以控制輸出在緩存中保留的時間。
(2)缺點:就像其他服務器端緩存功能一樣,輸出緩存仍然會消耗服務器上的資源。
2.4 在數據庫中維護狀態
當應用程序執行一個非常復雜或者相當花費時間的查詢時,可以將查詢的結果儲存在數據庫服務器上的一個單獨數據表中,而不是每次在用戶請求下一頁的結果時都要執行這個查詢[1]。
(1)優點:①無狀態性。②持久性。可以根據需要在盡可能長的時間內存儲數據庫信息,這些信息不受Web服務器可用性的影響。③安全性高。對數據庫的訪問要求嚴格的身份驗證和授權,這種訪問通常非常安全。④可伸縮性好、應用程序的性能高。使用這種方法即使數據量很大,對應用程序的性能影響也不會大。⑤可靠性和數據完整性。數據庫包括多種用于維護有效的功能,其中包括觸發器和引用完整性、事務等。通過在數據庫中(而不是在會話狀態等對象中)保存有關事務的信息,可方便地從錯誤恢復。⑥可訪問性。存儲在數據庫中的數據可供多種信息處理工具訪問。
(2)缺點:①復雜性。使用數據庫支持狀態管理意味著更復雜的硬件和軟件配置,這比將數據儲存在Session、Application、Cache、ViewState或者Cookie這樣的簡單對象或集合中更復雜。②性能降低。不佳的關系數據模型結構可能導致擴展問題,對數據庫執行過多的查詢可能會影響服務器性能。
3 結束語
綜上所述,對于安全性要求高的應用程序,應當使用在Web服務器上維護緩存數據的方式;伸縮性要求高的應用程序,應當使用在客戶端上維護緩存數據的方式。儲存的數據越多,加載頁面的時間越長,系統的性能就差。如果需要儲存大量特定于會話的數據,在數據庫中儲存數據是一種明智的選擇。
參考文獻
1 Sceppa D著,梁超,張莉,賀堃譯.ADO.NET技術內幕.北京:清華大學出版社,2003
2 McClure W B,Croft J J著,李萬紅譯.構建高度可伸縮的.NET數據庫應用程序.北京:清華大學出版社,2003
3 Dickinson P著,張曉明譯.ADO.NET高級編程.北京:中國電力出版社,2003
4 劉楊.突破C#編程實例五十講.北京:中國水利水電出版社,2002
5 陳英學.Microsoft ASP.NET深入編程.北京:北京希望電子出版社,2001
6 樂德廣.網絡緩存技術及應用的研究.計算機系統應用,2003;(5)
7 李用江.數據庫中大文本數據存取方法的探討.計算機系統應用,2004;(5)