ASP.NET緩衝管理的幾種方法_實用技巧

來源:互聯網
上載者:User

儘管緩衝管理在Windows應用程式中已經不再是個問題,但在web環境下依然是個挑戰。因為HTTP是一個無狀態的協議並且web服務無法識別不同請求的使用者。識別不同的請求究竟是哪個特定使用者發出的,並且儲存這些資訊以便它在以後請求中能被重新使用,對我們來說非常重要。ASP.NET提供了很多特性用來在用戶端和伺服器端儲存這些資料,但是有時我們會對“我們什麼時候使用它們(哪個)”感到疑惑。在ASP.NET中,我們會遇到像Session,Application以及Cache這些對象,為了有效地在web應用中有效地使用它們,理解他們之間的不同對我們來說非常重要。

背景

在這篇文章中,我將談到在ASP.NET中不同的緩衝管理方法。在web應用中,有時需要在服務端儲存資料以避免從資料庫檢索資料和資料格式化邏輯所需的開銷來提高效能,同時在接下來的請求中我們可以跨使用者、跨應用、跨機器地重用同樣的資料。所以,為了實現這個目的我們需要在服務端快取資料。

緩衝幫我們在3個方面實現了提高服務品質

•效能(Performance)-通過減少檢索資料和格式化操作開銷,緩衝提高了應用程式的效能。
•延展性(Scalability)-由於緩衝減少了檢索資料和格式化操作的開銷,它降低了服務端的負載,因而提高了應用程式的延展性。
•可用性(Availability)-由於應用程式從緩衝中讀取資料,應用程式可以在其它系統或資料庫連接失敗時繼續運行。
不同方法

在web應用中,我們可以在服務端和用戶端快取資料、頁面等。我們分別來看一下在服務端和用戶端緩衝。

服務端緩衝管理

ASP.NET Session state

Session用來緩衝每個使用者的資訊。這意味著這些資料是不能跨使用者共用的,它只限定了建立這個會話(Session)的使用者來使用它。ASP.NET中Session就是用來區分使用者的。

Session能用三種方式來託管:

•進程內(Inproc)-工作階段狀態儲存在aspnet_wp.exe進程中。當應用程式定義域回收時Session資料會丟失。
•狀態伺服器(StateServer)-工作階段狀態儲存在不同的進程內,可以在不同的機器上。因為它可以儲存在不同的機器上,所以這個選項支援網站群。
•Sql資料庫(SQLServer)-工作階段狀態儲存在SqlServer資料庫中,這個選項也支援網站群。
對於狀態伺服器和Sql資料庫來說,這兩者都需要對緩衝的對象進行序列化,因為要緩衝的資料是要緩衝到應用程式進程之外的。這兩種方式都會影響效能因為資料檢索與儲存需要話費更多時間相對進程內緩衝來說。所以要根據具體需要以確定使用哪種緩衝方式。

下面範例程式碼展示了如何使用Session

複製代碼 代碼如下:

string empNum = Request.QueryString["empnum"];
if (empNum != null)
{
    string details = null;

    if (Session["EMP_DETAILS"] == null)
    {
        //Get Employee Details for employee number passed
        details = GetEmployeeDetails(Convert.ToInt32(empNum));

        Session["EMP_DETAILS"] = details;
    }
    else
    {
        details = Session["EMP_DETAILS"];
    }

    //send it to the browser
    Response.Write(details);
}


ASP.NET application object

 ASP.NET提供了一個叫Application的對象用來儲存所有使用者都可以訪問的資料。這個對象的生命週期與應用程式的生命週期一樣,當應用程式啟動時這個對象會被重新建立。與Session對象不同,Application對象可以被所有使用者請求,因為這個對象是在應用程式定義域中建立和管理的,因而它也是不能在Web網站群中使用的。Application對象非常適合儲存應用程式中繼資料(Config file data),這種資料可以被裝載到Application對象中並且在整個應用程式周期中每個使用者請求都可以訪問其中的對象而不用重新裝載。但是如果有這樣的需求:在應用程式運行中無論什麼時候對Config檔案做了修改快取資料必需失效,這時Application方式就不能提供這樣的支援了。在這種情況下,就要考慮cache對象了,下面介紹cache對象的使用。

ASP.NET cache object

ASP.NET cache object是我最喜歡的緩衝機制,這是為什麼我在這裡要多說一些的原因。ASP.NET提供了一個鍵-值對(key-value pair)對象--cache對象,它可以在system.web.caching名稱空間中得到。它的範圍是應用程式定義域,生命週期和應用程式生命週期一致。與Session對象不同,它是可以被不同使用者來訪問的。

儘管Application和Cache對象非常相似,主要區別在於Cache對象有擁有更多的特性,像到期策略、緩衝依賴。它意味著資料存放區在緩衝對象可以根據預定義時間或它依賴的實體變化時到期或清楚,而這個特性Application對象是不支援的。

讓我們來討論下它支援的到期策略和緩衝的依賴吧。

依賴

依賴意味著緩衝的對象會被清除當依賴的實體發生變化時。所以可以定義一個依賴關係當依賴的對象發生變化時清除對應緩衝對象。ASP.NET支援了兩種依賴對象。

•檔案依賴(File Dependency)-它提供了這樣一種機制,當磁碟檔案無論何時發生變化時自動清除緩衝對象。舉例來說,我的應用程式使用XML儲存錯誤資訊(錯誤號碼和錯誤訊息的映射),用錯誤號碼來檢索錯誤訊息。每次當我想讀取錯誤訊息的時候,我不是每次都從磁碟去讀取,而是當應用啟動的時候將其放到Cache緩衝裡以便以後檢索的時候再用。在程式運行過程中,當我添加新的錯誤資訊或者修改已有的錯誤資訊時,會發生什麼情況呢?我需要停止程式運行去修改這些資訊嗎?根本不用,當做這樣修改的時候,Cache緩衝中的資料會自動失效,這就是檔案快取依賴。
下面例子顯示了如何使用檔案快取來使Cache緩衝失效的。所以,無論任何時候對error.xml檔案作出修改時,緩衝條目都會自動失效。

複製代碼 代碼如下:

object errorData;
 //Load errorData from errors.xml
 CacheDependency fileDependency =
     new CacheDependency(Server.MapPath("errors.xml"));
 Cache.Insert("ERROR_INFO", errorData, fileDependency);

•鍵依賴(Key Dependency)-鍵依賴和檔案依賴非常相似,唯一的區別在於它不是依賴檔案而是依賴其它條目,當Cache依賴的條目發生改變時或被刪除時,緩衝會自動失效。這種方法對相互依賴的對象增加到緩衝中,而且當主對象發生變化時這些相互依賴的緩衝對象都要被釋放的情況下很有用。例如,員工號、姓名、薪水同時增加到了緩衝當中,如果員工號發生了改變或被刪除,所有緩衝中的員工資訊都會被清除。在這個例子中,員工號在員工資訊中充當依賴項。
下面例子顯示了如何使用鍵依賴來使緩衝失效的。

複製代碼 代碼如下:

string[] relatedKeys = new string[1];
relatedKeys[0] = "EMP_NUM";
CacheDependency keyDependency = new CacheDependency(null, relatedKeys);
Cache["EMP_NUM"] = 5435;
Cache.Insert("EMP_NAME", "Shubhabrata", keyDependency);
Cache.Insert("EMP_ADDR", "Bhubaneswar", keyDependency);
Cache.Insert("EMP_SAL", "5555USD", keyDependency);

到期策略(Expiration Policy)

到期策略定義了如何以及何時讓緩衝的對象到期的。

•基於時間的到期(Time based expiration)-基於時間的到期提供了讓使用者為緩衝對象預定義到期的時間。這個預定義時間可以是一個絕對時間如到2005年10月31號12點,或者相對時間,相對於緩衝對象的存入時間。

複製代碼 代碼如下:

//Absolute Expiration
Cache.Insert("EMP_NAME", "Shubhabrata", null,
             DateTime.Now.AddDays(1), Cache.NoSlidingExpiration);

//Sliding Expiration
Cache.Insert("EMP_NAME", "Shubhabrata", null,
             Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(60));


怎樣知道一個緩衝對象被清除了?

上面的例子描述了如何清除緩衝對象,但有時我們需要知道什麼時候對象從緩衝中清除。可以,我們通過使用回調來實現。在上面錯誤資訊的例子中,無論任何時候error.xml發生變化時,緩衝的對象就會被清除。假設我們想要更新緩衝與最新的錯誤訊息。何時從緩衝中清除對象,我們可以使用回調(Callback)來做進一步處理(重新載入對象到緩衝中)。

下面例子顯示了如何在緩衝到期時使用回調的情境。

複製代碼 代碼如下:

private void AddItemsToCache()
{   
    int empNum = 5435;
    CacheItemRemovedCallback onEmpDetailsRemove =
                    new CacheItemRemovedCallback(EmpDetailsRemoved);
    Cache.Insert("EMP_NUM", empNum, null,
                              Cache.NoAbsoluteExpiration,
                              Cache.NoSlidingExpiration,
                              CacheItemPriority.Default,
                              onEmpDetailsRemove);
}

private void EmpDetailsRemoved(string key, object val,
                              CacheItemRemovedReason reason)
{
    //When the item is expired
    if (reason == CacheItemRemovedReason.Expired)
    {
        //Again add it to the Cache
        AddItemsToCache();<BR>    }
}


在上面的例子中,你必須注意CacheItemPriority這個參數,它和Callback參數一起使用。CacheItemPriority用來設定增加到緩衝中的對象的優先順序。這個優先權告訴Cache當記憶體一旦很低時,這個優先順序會指示對象的釋放順序。這個過程被稱為清除(scavenging)。

.NET Remoting

你也許會想.NET remoting如何用於資料緩衝?當我第一次聽到這個問題時,這個問題就進到了我的腦海中。正如你所知道的.NET Remoting通過單例把對象共用給各個用戶端,所以使用單例的對象可以用來快取資料以共用資料給各個不同的用戶端。因為.NET Remoting可以運行在進程和機器之外,當我們想要緩衝對象並且跨服務、跨使用者、尤其是用在網站群時,這個特性非常有用。這種方法我們可以將資料緩衝到單例對象的資料成員裡並且提供方法去讀取和儲存資料。當我們實現這種方法時,我們必須確保緩衝的remoting對象不被記憶體回收行程清除了。因而我們必須設定Remoting對象的緩衝永不到期以至永遠不會逾時。我們可以重寫InitializeLifetimeService和MarshalByRefObject方法使它們返回Null。但是這樣做的主要問題是效能,通過分析使用這種方法比其它方法的效能都差。不管怎樣,應該由設計師或開發人員根據具體需求選擇出最合適的方法。

記憶體對應檔(Memory-Mapping files)

大家都知道記憶體對應檔是什麼,它基於映射到物理磁碟上的檔案到應用程式儲存空間的一個特定的位址範圍。這種方式允許不同的進程使用相同的資料從而增加應用程式的效能。因為使用記憶體對應檔在ASP.NET應用中並不流行,我個人也不建議使用這種方法因為它增加了程式的複雜性,並且.NET Framework也不支援這樣。但是如果有人喜歡使用這種方法的話,他必須為他們的需求開發出自訂的解決方案。

靜態變數(Static variables)

我們可以使用靜態變數來儲存全域的資料或對象,以便在整個應用程式生命週期來訪問它。同樣地,我們也可以使用靜態對象來快取資料,並且可以提供方法來從緩衝中檢索和儲存資料。因為靜態Object Storage Service在進程中,效能非常快。但是用靜態變數實現到期策略和緩衝依賴是非常複雜的,我還是比較喜歡使用Cache相比用靜態變數。另一個問題是使用者自訂緩衝對象必須是安全執行緒的,所以實現它必須特別小心。

自訂靜態緩衝可以用下面方法實現:

複製代碼 代碼如下:

public class CustomCache
{
    //Synchronized to implement thread-safe
    static Hashtable _myCache =
             Hashtable.Synchronized(new Hashtable());

    public static object GetData(object key)
    {
        return _myCache[key];
    }

    public static void SetData(object key, object val)
    {
        _myCache[key] = val;
    }
}

資料庫

我們可以使用資料庫來儲存資料來實現跨使用者、跨機器的資料共用。當我們想要緩衝非常大的資料對象時,這是一種非常好的方式。使用這種方式來儲存小的資料是得不償失的(效能低),用於儲存少量資料可以尋找其它進程內的緩衝機制。儲存到資料庫中的快取資料需要經過序列化成XML來方便儲存和檢索,在.NET Framework中我們也可以使用其它類型的序列化格式。

網頁輸出快取(ASP.NET page output caching)

有時,我們的web應用程式在一定的時間範圍內對於某些頁面來說是不會變化的,例如HR網站中,員工工資資訊不會頻繁地變動,它們在一個月一般只變動一次。一般來說都是在一個月的第一天發生變化。所以,對特定的員工來說,一個月中這個員工的頁面內容是不會變化的。所以,把這些頁面在伺服器上緩衝起來以避免每次請求重新計算的過程,這真是個不錯的主意。為了達到這個目的,.NET為我們提供了在服務端指定特定時間緩衝輸出頁面的特性;它也提供了快取頁面面片段的特性。在這兒我不再詳細去描述這種緩衝方法了,因為網路上有很多關於這方面的詳細介紹。這是一個非常長的部分如果我們現在討論它,我計劃在其它章節去討論它。

複製代碼 代碼如下:

<!-- VaryByParm - different versions of same page will be
cached based on the parameter sent through HTTP Get/Post
Location - where the page is cached -->
<%@OutputCache Duration="60" VaryByParam="empNum"
                                       Location="Server"%>

我們來對比一下我們所討論的這些緩衝:

方法  是否支援網站群? 備忘

ASP.NET Session State
- InProc
- StateSerer
- SQLServer


No
Yes
Yes

Unlike other option, it stores only user session specific data
ASP.NET Application Object No  
ASP.NET Cache Object No  
.NET Remoting Yes  
Memory-Mapped files No  
Static Variables No  
Database Yes  
ASP.NET Page Output Caching No  

用戶端緩衝管理

在上面章節中我們討論了在服務端的不通緩衝方式,但有時我們希望能在用戶端快取資料和頁面以提高效能。使用用戶端緩衝可以降低服務端的負載壓力,但這種緩衝機制卻存在安全問題因為資料是儲存在用戶端。在用戶端緩衝也有不同的方式,我將簡單地談到幾種。

Cookies

Cookie對web開發人員中是非常熟悉的概念,Cookie儲存在用戶端,當用戶端每次發送請求時都會將它發送到服務端,服務端響應時也會把它發回到用戶端。因為它限制了位元組數(4096個位元組),所以它只能緩衝比較小的資料。它可以使用到期策略使它在一段特定的時間之後失效。下面的例子顯示了在ASP.NET中如何使用Cookie。

複製代碼 代碼如下:

if (this.Request.Cookies["MY_NAME"] == null)
{
    this.Response.Cookies.Add(new HttpCookie("MY_NAME",
                                       "Shubhabrata Mohanty"));
}
else
{
    this.Response.Write(this.Request.Cookies["MY_NAME"].Value);
}

ViewState

.NET ViewState是一個新的概念。和頁面相關的資料和控制項都是儲存在ViewState,這些保留值可以跨多個請求道伺服器。如果你還記得,在VB-ASP應用開發中跨多個請求儲存資料是通過Hidden控制項的。事實上ViewState在ASP.NET是隱藏控制項的內部實現,但對比隱藏控制項它做了散列化以增加安全性。去看ViewState是如何?的,你可以開啟頁面查看原始碼。ViewState也不能儲存大量資料因為它每個請求都會發送到服務端。

複製代碼 代碼如下:

protected void Page_Load(object sender, EventArgs e)
{
    if (this.ViewState["MY_NAME"] == null)
    {
        this.ViewState["MY_NAME"] = "Shubhabrata Mohanty";
    }

    //txtName is a TextBox control
    this.txtName.Text = this.ViewState["MY_NAME"].ToString();
}

Hidden fields

Hidden field在VB-ASP Web開發中非常流行。Hidden fields和其它控制項的使用非常相似,但它在輸出頁面上是看不到的。和ViewState一樣它也不能儲存大量資料。註:隱藏架構(Hidden frames)可以在用戶端快取資料,但不是所有瀏覽器都支援隱藏架構。

複製代碼 代碼如下:

<!--In ASP.NET-->
<asp:HiddenField ID="myHiddenField" Value="Shubhabrata"
                                             runat="server" />
<!--In HTML-->
<input id="myHiddenField" type="hidden" value="Shubhabrata" />

微軟IE瀏覽器緩衝

因為我們是在談論微軟的ASP.NET,為什麼不討論一下微軟的另外一種緩衝能力呢?微軟的IE瀏覽器提供了另一種機制在用戶端快取頁面面,這可以使用EXPIRES設定指令添加到HTML頁面或在IIS中手動設定。到IIS中的HTTP標籤屬性視窗,然後選擇使內容到期複選框。我們可以使用這個設定在用戶端緩衝靜態網頁和圖片。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.