12
6-6 聖殿祭司的 ASP.NET 3.5 專家技術手冊 II 新功能篇 使用 C# 6-3 ASP.NET 執行管線與快取原理 ASP.NET 有點基礎的人或多或少都聽過:「ASP.NET 第一執行網 頁會較慢,因為系統會執行網頁編譯動作,故第一次執行時會察覺到網 頁有些停頓或緩慢;而第二次再執行相同網頁,系統就會以編譯過的程 式來回應 Request 請求,故第二次以後執行效能就會快很多。」這是大家 常耳熟能詳的一個論調,相信各位應不陌生才是。 但為什麼要提這點?理由是若要解釋快取(Cache)之所以能夠加速 網頁運作的原因,前提是必須要先瞭解 ASP.NET 執行管線是如何運行 的,從 ASP.NET 執行過程中,剛好可以找到 ASP.NET 第一執行網頁會 較慢,第二次以後速度較快的理由;若進一步在 ASP.NET 執行管線中加 入快取機制時,快取會如何改變系統運作流程,進而再次加速網頁運作 效能,以致快取可以比單純編譯過後的網頁效能還快。 祭司將介紹與解釋下面兩個原理,並且加以比較,各位就會明白為 什麼快取的對網頁執行速度的增強。 1. ASP.NET 執行管線(Pipeline)運作原理。 2. ASP.NET 快取運作原理。 下圖為 ASP.NET 執行管線的流程圖(沒有加入快取設定),當使用 者第一次執行網頁 Page.aspx 時,其運作過程為:nBrowser 瀏覽器發出 第一個網頁 Request 請求,系統首先會 Parse 解析網頁Îo進而呼叫 Compiler 編輯程式 Îp 將網頁程式轉換為 Assembly Intermediate LanguageÎq最後系統再經由 JIT 編譯器將 Assembly IL 轉換成特定 CPU 類型(如 x86 x64)所能執行的指令Îr Web Server HTML 頁面回 傳給 Browser 瀏覽器,並顯示最後結果在畫面上,如此便完成網頁執行 的過程。

6-3 ASP.NET 執行管線與快取原理download.microsoft.com/download/7/4/b/74bac805-ecb...asp.net 3.5 專家技術手冊ii 新功能篇 — 使用c# 6-3 asp.net執行管線與快取原理

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

6-6

聖殿祭司的 ASP.NET 3.5 專家技術手冊 II 新功能篇 — 使用 C#

6-3 ASP.NET 執行管線與快取原理

對 ASP.NET 有點基礎的人或多或少都聽過:「ASP.NET 第一執行網

頁會較慢,因為系統會執行網頁編譯動作,故第一次執行時會察覺到網

頁有些停頓或緩慢;而第二次再執行相同網頁,系統就會以編譯過的程

式來回應 Request 請求,故第二次以後執行效能就會快很多。」這是大家

常耳熟能詳的一個論調,相信各位應不陌生才是。

但為什麼要提這點?理由是若要解釋快取(Cache)之所以能夠加速

網頁運作的原因,前提是必須要先瞭解 ASP.NET 執行管線是如何運行

的,從 ASP.NET 執行過程中,剛好可以找到 ASP.NET 第一執行網頁會

較慢,第二次以後速度較快的理由;若進一步在 ASP.NET 執行管線中加

入快取機制時,快取會如何改變系統運作流程,進而再次加速網頁運作

效能,以致快取可以比單純編譯過後的網頁效能還快。

祭司將介紹與解釋下面兩個原理,並且加以比較,各位就會明白為

什麼快取的對網頁執行速度的增強。

1. ASP.NET 執行管線(Pipeline)運作原理。

2. ASP.NET 快取運作原理。

下圖為 ASP.NET 執行管線的流程圖(沒有加入快取設定),當使用

者第一次執行網頁 Page.aspx 時,其運作過程為: Browser 瀏覽器發出

第一個網頁 Request 請求,系統首先會 Parse 解析網頁 進而呼叫

Compiler 編輯程式 將網頁程式轉換為 Assembly Intermediate Language 最後系統再經由 JIT編譯器將 Assembly IL轉換成特定 CPU類型(如 x86 或 x64)所能執行的指令 Web Server 將 HTML 頁面回

傳給 Browser 瀏覽器,並顯示最後結果在畫面上,如此便完成網頁執行

的過程。

6-7

Cache 2.0 第二代的網頁快取機制 I ~ 網頁輸出快取

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17

圖 6-4 ASP.NET 執行流程圖(第一次,無快取機制)

然而下圖是第二次執行相同的網頁 Page.aspx,系統會略過 Parse 解

析與 Compile Assembly IL 兩個階段,由原來的五個執行階段減為三個,

並且由於節省了兩個階段的執行工作,可以節省不少額外的時間,因此

第二次以後的所有網頁 Request 請求,會比第一次快很多的原因在此。

圖 6-5 ASP.NET 執行流程圖(第二次,無快取機制)

6-8

聖殿祭司的 ASP.NET 3.5 專家技術手冊 II 新功能篇 — 使用 C#

雖然編譯式的網頁程式較傳統直譯式的網頁程式執行效能快,但是

人類對於效能的渴望是永遠不滿足的,那是否有辦法再進一步提升編譯

後的網頁執行速度?有,答案就是使用快取(Cache)來再次縮短 ASP.NET執行管線,便可以得到更短的網頁 Response 回應時間。

下圖中,我們在傳統的 ASP.NET 網頁中加入快取機制,其第一次執

行 Page.aspx 網頁後,便會將最終的 HTML Render 輸出快取在記憶體之

中(圖 6-6 的第 階段);而當第二次再執行 Page.aspx 網頁時(圖 6-7),整個執行過程會略過 Parse、Compiler 與 Assembly IL 三個階段,且系統

連動態運算生成或資料庫存取的動作都略過,直接將快取記憶體中的

HTML Render 回傳給 Browser 瀏覽器顯示。故各位可以比較圖 6-5 與圖

6-7,同樣是第二次以後執行的過程,前者沒有加入快取,而後者有加入

快取,前者需要三個階段,後者只需二個階段,並且連 Init、Load、Render的運算階段都省略了,省掉了一堆 CPU 計算與資料庫存取等等,無怪乎

快取具有無與倫比的執行效能,各位應能理解了吧。

圖 6-6 ASP.NET 執行流程圖(第一次,有快取機制)

6-9

Cache 2.0 第二代的網頁快取機制 I ~ 網頁輸出快取

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17

圖 6-7 ASP.NET 執行流程圖(第二次,有快取機制)

6-4 網頁輸出快取之完整網頁快取

網頁輸出快取(圖 6-3)是 ASP.NET 2.0 快取架構兩大類型之一,其

目的是針對網頁 Page 來進行快取,而其又可細分為: 完整網頁快取、

部分網頁快取,本小節主要是談完整網頁快取(Full Page Caching),

而部分網頁快取(Partial Page Caching)則挪到下一小節再談。

6-4-1 完整網頁快取基本觀念

所謂的完整網頁快取(Full Page Caching)就是針對整個網頁 Page頁面進行快取,其所儲存的是第一次網頁執行後,Page 頁面最終的 HTML Render 呈現畫面資料。除了第一次是必須經過 ASP.NET 動態運算生成,

包括了:商業邏輯運算、資料庫存取、控制項生成等等瑣碎工作,最終

會形成一堆 HTML 的標籤回傳給使用者端的 Browser 瀏覽器,進而呈現

畫面;而這個最終的一堆 HTML 標籤就會被快取到記憶體之中,往後第

二次以後的所有 Request 請求,伺服器皆會直接把快取所保存的 HTML

6-10

聖殿祭司的 ASP.NET 3.5 專家技術手冊 II 新功能篇 — 使用 C#

標籤回傳給使用者端的瀏覽器,如此 Response 回應速度便會快很多(圖

6-3)。

而網頁輸出快取可以使用兩種方式來達成:

1. 以<%@ OutputCache … %>指示詞宣告(高階)。

2. 以 Response.Cache 的程式化 API 方式設定(低階)。

@ OutputCache 指示詞宣告

如果要對一個網頁 Page 加入完整網頁快取 60 秒,你可以在.aspx網頁中加入一段語法宣告:

<%@ OutputCache Duration="60" VaryByParam="None" %>

Response.Cache 的程式化 API 語法

若以程式化 API 方式,在 Code-Behind 程式中設定 60 秒的網頁

快取,語法如下:

Response.Cache.SetExpires(Now.AddSeconds(60));

然而在深入解釋@ OutputCache 指示詞和 Response.Cache 的程式化

API 之前,我們先來練習兩個簡單例子,讓大家有實際初步的概念。

範例 6-1 以@ OutputCache 指示詞宣告網頁輸出快取

本範例示範在一個普通的 .aspx 網頁加入快取機制,利用 @ OutputCache 指示詞將整個網頁 Page 快取 60 秒,請參考 FullPageCaching. aspx 程式,步驟說明如下:

圖 6-8 以@OutputCache 宣告完整網頁快取

員工資料庫

快取起始時間

6-11

Cache 2.0 第二代的網頁快取機制 I ~ 網頁輸出快取

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17

:建立 GridView 與 SqlDataSource 控制項

畫面中透過 GridView 與 SqlDataSource 控制項顯示 Northwind 資料庫中

Employees 員工資料。

:加入@ OutputCache 指示詞宣告

請切換到【原始檔】模式,在@ Page 指示詞該行之後,加入@ OutputCache指示詞宣告網頁快取,程式碼如下:

<%@ Page Language="C#" ... %>

<%@ OutputCache Duration="60" VaryByParam="None" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>未命名頁面</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<asp:GridView ID="GridView1" runat="server" ...>

...略

</asp:GridView>

</div>

<asp:SqlDataSource ID="SqlDataSource1" ...>

</asp:SqlDataSource>

</form>

</body>

</html>

:加入快取起始時間顯示

請在 FullPageCaching.aspx 加入顯示快取時間程式:

01 protected void Page_Load(object sender, EventArgs e) 02 { 03 Response.Write("快取網頁起始時間:" + DateTime.Now.ToLongTimeString());

04 }

SStteepp 33

SStteepp 22

SStteepp 11

STEP 1

6-12

聖殿祭司的 ASP.NET 3.5 專家技術手冊 II 新功能篇 — 使用 C#

程式說明:

其實整個範例只有一個重點,就是在 Step 2 加入一行 <%@ OutputCache …>宣告,如此網頁 Page 就完成了快取設定。

然而在圖 6-8 執行畫面中,有兩個地方是值得加以探討的: 快取起

始時間、 員工資料庫,範例中這兩個部分並非純粹好玩的,而是刻意

設計的,理由是快取設定後,是無法視覺化看到快取的,故我們必須透

過第三者來顯現快取的能力,您可以進行兩個測試動作,來確認快取作

用的真實性:

測試一:重新整理網頁(Refresh)測試

請在 IE 瀏覽器按下【重新整理】圖示,將網頁重新整理,時間

顯示格式是“時:分:秒”,但您可以發現無論您重新整理網頁

幾次,時間仍是固定不動,為什麼會這樣,這說明了什麼?您可

以參考 ASP.NET 執行流程圖(圖 6-7)的說明,當網頁快取後,

就不再執行 Init、Load、Render 的運算階段,當然也不會再執行

Code-Behind 時間顯示的程式碼,而是將記憶體中的快取直接回

應給前端瀏覽器,因此您才會看到時間是原始的快取,必須等待

60 秒後,快取才會失效,進而重新進行快取。

測試二:修改 Employees 資料記錄測試

在執行網頁後,您可立刻修改 SQL Server 資料庫的 Employees

員工資料,並加以儲存,然後重新 Refresh 網頁畫面,您會發現

GridView 資料仍然是舊的員工資料,這說明了快取正在作用(測

試的所有動作必須在快取後的 60 秒內完成)。

故經由以上兩個測試,我們可以百分之百確認快取存在的真實性

了,也能更直接體會快取作用的現象。

範例 6-2 以 Response.Cache 的程式化 API 設定網頁輸出快取

上一個範例是透過@OutputCache 指示詞宣告網頁快取,如果你想用

程式化 API 方式在 Code-Behind 中宣告也可以,請參考 FullPageCaching API.aspx 程式:

6-13

Cache 2.0 第二代的網頁快取機制 I ~ 網頁輸出快取

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17

01 protected void Page_Load(object sender, EventArgs e) 02 { 03 //加入快取宣告,設定快取過期時間為 60 秒

04 Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)); 05 Response.Cache.SetCacheability(HttpCacheability.Public); 06 07 Response.Write("快取網頁起始時間:" + DateTime.Now.ToLongTimeString());

08 }

程式說明:

原則上是只要設定 Cache.SetExpires()過期時間就可以了,但祭司實

地測試發現,您必須進一步將 HttpCacheability 設定為 Public,則快取才

會正常作用。

在面對網頁輸出快取方式有兩種 指示詞宣告、 程式化 API,撇開

個人喜好的因素外,兩者之間還是有不同適用的情況,如@ OutputCache指示詞宣告適合用在「如果在設計階段(Design time)就知道網頁的快

取性設定需求,就可以用宣告方式設定快取性。」而程式化 API 適合用

在「如果應用程式會根據執行階段(Runtime)條件判斷快取性,例如讀

取要求標頭,就可以用程式設計方式設定快取性。」此為一個判斷適用

性的準測。

6-4-2 @OutputCache 指示詞詳解

在做過上面兩個範例後,以下將進一步解釋網頁輸出快取的@ OutputCache 指示詞,以下是@ OutputCache 指示詞宣告完整語法:

<%@ OutputCache

Duration="#ofseconds"

Location="Any | Client | Downstream | Server | None | ServerAndClient "

Shared="True | False"

VaryByControl="controlname"

VaryByCustom="browser | customstring"

VaryByHeader="headers"

VaryByParam="parametername"

CacheProfile="cache profile name | ' ' "

NoStore="true | false"

SqlDependency="database/table name pair | CommandNotification"

%>

6-14

聖殿祭司的 ASP.NET 3.5 專家技術手冊 II 新功能篇 — 使用 C#

以上語法中粗體字部分是 Cache 2.0 所增加的新功能,各位可以對照

下面 Cache 1.0 舊語的@ OutputCache 指示詞語法:

<%@ OutputCache

Duration="#ofseconds"

Location="Any | Client | Downstream | Server | None"

Shared="True | False"

VaryByControl="controlname"

VaryByCustom="browser | customstring"

VaryByHeader="headers"

VaryByParam="parametername"

%>

@ OutputCache 指示詞其參數意義說明如下(約略看過即可):

1. Duration

網頁或使用者控制項被快取的時間,以秒為單位。在網頁或使用

者控制項上設定這個屬性,會建立 HTTP 從物件回應的過期原

則,並且會自動快取網頁或使用者控制項輸出。

這是必要屬性。如果您不包含它的話,就會發生剖析器(Parser)

錯誤。

2. Location

Location 是來控制資源輸出快取 HTTP 回應的位置。而 Location是 OutputCacheLocation 其中一個列舉值,而完整的列舉值成員

說明如下表。

表 6-1 OutputCacheLocation 列舉成員

成員名稱 說明

Any(預設值)

輸出快取可以位在瀏覽器用戶端 (要求的來源)、參予

要求的 Proxy 伺服器 (或任何其他的伺服器) 或要求已

處理的所在伺服器上。這個值對應於 HttpCacheability. Public 列舉值。

6-15

Cache 2.0 第二代的網頁快取機制 I ~ 網頁輸出快取

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17

成員名稱 說明

Client 輸出快取位在要求所來自的瀏覽器用戶端。這個值對

應於 HttpCacheability.Private 列舉值。

Downstream

輸出快取可以儲存在任何 HTTP 1.1 快取功能裝置中,

而不可以儲存在來源伺服器中。這包含 Proxy 伺服器

和提出要求的用戶端。

None 輸出快取會針對要求的頁面停用。這個值對應於 HttpCacheability.NoCache 列舉值。

Server 輸出快取位在要求已處理的 Web 伺服器上。這個值對

應於 HttpCacheability.Server 列舉值。

ServerAndClient

輸出快取只可以儲存在原始伺服器或提出要求的用戶

端。Proxy 伺服器不能快取回應。這個值對應於

HttpCacheability.Private 和 HttpCacheability.Server 列舉

值的組合。

3. Shared

Shared 是用來決定使用者控制項輸出是否可以與多重網頁共

用。其為布林 (Boolean) 值,預設值為 false。

1. ASP.NET Web網頁(.aspx 檔案)包含的@ OutputCache指示

詞不支援 Shared這個屬性。

2. 只有部分網頁快取有支援 Share功能,而完整網頁快取則不支

援。

4. VaryByControl

用來變更使用者控制項輸出快取的分號分隔字串清單。這些字串

表示在使用者控制項中所宣告之ASP.NET伺服器控制項的 ID屬

性值。

5. VaryByCustom

表示自訂輸出快取需求的任何文字。如果這個屬性被賦予

Browser 的值,那麼快取將會依瀏覽器名稱和主要版本資訊而不

6-16

聖殿祭司的 ASP.NET 3.5 專家技術手冊 II 新功能篇 — 使用 C#

同。如果輸入自訂字串,您就必須覆寫在應用程式之 Global.asax 檔案中的 GetVaryByCustomString 方法。

6. VaryByHeader

用來變更輸出快取之分號分隔的 HTTP 標頭清單。當這個屬性設

定為多個頁首時,輸出快取便會包含每個指定頁首組合所要求文

件的不同版本。

7. VaryByParam

用來變更輸出快取的分號分隔的字串清單。根據預設,這些字串

對應至以 GET 方法屬性傳送的查詢字串值,或是使用 POST 方法傳送的參數。當這個屬性被設定為多個參數時,輸出快取便會

包含每個指定參數組合所要求文件的不同版本。可能的值包括 none、星號 (*),以及任何有效的查詢字串或 POST 參數名稱。

8. CacheProfile

要與網頁關聯之快取設定的名稱。這是選擇性屬性,預設值為空

字串 ("")。

9. NoStore

布林 (Boolean) 值,決定是否防止敏感資訊的次要儲存區。

使用者控制項(.ascx 檔案)包含的 @ OutputCache 指示詞不支

援 NoStore這個屬性。將這個屬性設定為 true,相當於 Runtime

時期的程式 Response.Cache.SetNoStore();

10. SqlDependency

字串值,用以辨識網頁或控制項之輸出快取所相依的資料庫集和

資料表名稱組。請注意,SqlCacheDependency 類別會監視輸出

快取所相依之資料庫中的資料表,因此當資料表中的項目更新

時,這些項目便會在使用資料表架構的輪詢時從快取移除。在以 CommandNotification 值使用通知時 (在 Microsoft SQL Server 2005 中),SqlDependency 類別最終會用來向 SQL Server 2005 伺服器註冊查詢通知。

6-17

Cache 2.0 第二代的網頁快取機制 I ~ 網頁輸出快取

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17

SqlDependency 屬性的 CommandNotification值只會在 Web網

頁 (.aspx)上有效。使用者控制項只能使用運用@ OutputCache

指示詞的資料表架構輪詢。

最後,@ OutputCache 指示詞必須和 VaryByParam 或 VaryByControl二者之一同時搭配使用,這是最基本的要求,例如:

<%@ OutputCache Duration="60" VaryByParam=" " %>

<%@ OutputCache Duration="60" VaryByControl=" " %>

6-4-3 Response.Cache 的程式化 API 說明

前一小節雖然將@ OutputCache 指示詞所有參數詳細列出,但可別以

為快取的設定全部都講完了,事實上在程式化快取 API 部分,仍然有許

多屬性、功能與方法是@ OutputCache 指示詞裡面所沒有的,有許多知識

面要進一步地來探索。

回顧範例 6-2 中,我們使用下列 API 程式來宣告網頁的快取:

Response.Cache.SetExpires(Now.AddSeconds(60));

Response.Cache.SetCacheability(HttpCacheability.Public);

關鍵指令是 Response.Cache 屬性,它是用以取得網頁快取原則

(Caching Policy),包括了:到期、私密性與 Vary 子句等等,因此某些

方面,我們可以將設定快取視為一堆原則(ploicy)的設定,以便讓系統

知道我們所希望的快取是長什麼樣子。既然快取等於是在設定 Policy 原

則,若更進一步探究這個 Policy,其實背後指的就是 HttpCachePolicy 類

別,下圖是 HttpCachePolicy 重要屬性與方法。