不管使用哪種底層平台,可靠性和效能都是對所有 Web 應用程式的主要要求,儘管從某種意義上講,這兩個要求是相互矛盾的。例如,要構建更可靠、更健壯的應用程式,可能需要將 Web 服務器與具體的應用程式分離,使應用程式在進程外工作。但是,如果在不同於 Web 服務器進程的記憶體環境中工作,應用程式將變慢。因此,需要採取合理的措施,以確保進程外代碼儘可能快地運行。
在構建 Microsoft? ASP.NET 運行時環境時,依據的設計原則即:充分考慮可靠性和效能。得到的 ASP.NET 進程模型包含了兩個系統元素 - 一個存在於 Web 服務器進程中的進程內連接器,一個外部的輔助進程。另外,ASP.NET 運行時結構的可伸縮能力很強,可以自動使用多處理器硬體中任意選定的處理器。這種模式被稱為“Web Garden”,它可以使多個輔助進程同時運行,而且各個進程均在獨立的處理器中。
高度概括起來,ASP.NET 運行時具有三大屬性:
應用程式和 ASP.NET 輔助進程之間完全分離。提供服務的輔助進程的壽命決不會影響應用程式的壽命。換句話說,當應用程式啟動並處於運行狀態時,輔助進程可以隨時終止。
儘管 ASP.NET 應用程式從不在 Web 服務器內採用進程內的方式運行,但大多數情況下,其總體效能仍接近於進程內應用程式的效能。
為 Web Garden 體繫結構提供了內建的和可配置的支援。只要簡單檢查一下設定檔中的設定,輔助進程就可以複製自己,以利用所有與進程密切相關的 CPU。因此,在大多數情況下,您在具備多處理器的電腦中獲得的可縮放性將呈線性增長的趨勢。(本文後面將詳細介紹此內容。)
本文將介紹 ASP.NET 運行時環境的組成元素,然後一步一步地講述從 URL 請求變為純 HTML 文本的“漫長而曲折”的過程。
除非另有說明,否則以下介紹中均指 ASP.NET 的預設進程模型,即 Microsoft? Internet Information Services (IIS) 5.x 中唯一的模型。
ASP.NET 結構的組件
執行 ASP.NET 應用程式需要宿主 Web 服務器的支援。在 Microsoft? Windows? 的 Server 平台中,Web 服務器由名為 inetinfo.exe 的 IIS 可執行檔表示。Windows 2000 及以上版本的作業系統本身均提供了 Web 服務器。但需要注意,在 Microsoft? Windows Server 2003 中,並未預設安裝 IIS 和 ASP.NET,必須通過單擊“控制台”中的“添加或刪除程式”小程式將其添加到系統中。
只有少數幾種被用戶端請求的資源類型由 IIS 直接處理。例如,對 HTML 頁面、文字檔、JPEG 和 GIF 映像的傳入請求由 IIS 處理。對 Active Server Page (*.asp) 檔案的請求通過調用名為 asp.dll 的 ASP 專用擴充模組進行解析。同樣,對 ASP.NET 資源(例如,*.aspx、*.asmx、*.ashx)的請求將傳遞到 ASP.NET ISAPI 擴充。該系統組件是一個名為 aspnet_isapi.dll 的 Win32 DLL。ASP.NET 擴充可以處理多種資源類型,包括 Web 服務和 HTTP 處理常式調用。
ASP.NET ISAPI 擴充是一個 Win32 DLL,未整合Managed 程式碼。它是接收和指派對各種 ASP.NET 資源的請求的控制中心。按照設計,該模組存在於 IIS 進程中,在具有管理員權限的 SYSTEM 帳戶下運行。開發人員和系統管理員不能修改此帳戶。ASP.NET ISAPI 擴充負責調用 ASP.NET 輔助進程 (aspnet_wp.exe),而該進程又負責控制請求的執行。除了對請求進行安排以外,ASP.NET ISAPI 還監視輔助進程的運行情況,並在效能降低到一定程度時將進程取消。
輔助進程是一小段 Win32 shell 代碼,整合了公用語言運行庫 (CLR) 並運行Managed 程式碼。它負責處理對 ASPX、ASMX 和 ASHX 資源的請求。一般來說,此進程在一台給定的電腦中只有一個執行個體。所有當前啟用的 ASP.NET 應用程式均在其中運行,每個應用程式都位於一個獨立的 AppDomain 中。但是,如前所述,輔助進程支援 Web Garden 模式,即進程的相同副本都運行在與進程密切相關的 CPU 中。(更多內容,請參閱本文後面的“Web Garden 模型”部分。)
ISAPI 和輔助進程之間的通訊是使用一組具名管道進行的。具名管道是一種 Win32 機制,用於跨進程邊界傳輸資料。顧名思義,具名管道的工作方式與管道相似:在一端輸入資料,在另一端輸出相同的資料。建立的管道既可以串連本地進程,也可以串連遠端電腦上啟動並執行進程。對於本地進程間通訊,管道是 Windows 中的最有效、最靈活的工具。
儘管 ASP.NET ISAPI 和輔助進程是 ASP.NET 運行時結構的主要組成部分,但還有其他一些可執行檔也發揮著作用。下表列出了所有這些組件。
表 1:構成 ASP.NET 運行時環境的可執行檔
名稱 類型 帳戶
aspnet_isapi.dll Win32 DLL(ISAPI 擴充) LOCAL SYSTEM
aspnet_wp.exe Win32 EXE ASPNET
aspnet_filter.dll Win32 DLL(ISAPI 篩選器) LOCAL SYSTEM
aspnet_state.exe Win32 NT Service ASPNET
aspnet_filter.dll 組件是一個小的 Win32 ISAPI 篩選器,用來備份 ASP.NET 應用程式的無 Cookie 工作階段狀態。在 Windows Server 2003 中,當啟用 IIS 6 進程模型時,aspnet_filter.dll 還將篩選出 Bin 目錄中對非可執行資源的請求。
aspnet_state.exe 的作用對 Web 應用程式更為重要,因為它用於管理工作階段狀態。該項服務是可選的,可以用來在 Web 應用程式記憶體空間之外儲存工作階段狀態資料。該可執行檔是一種 NT 服務,既可以在本地運行,也可以遠程運行。當該服務被啟用後,可以將 ASP.NET 應用程式配置為將所有會話資訊儲存在此進程的記憶體中。一種類似的方案是提供更為可靠的資料存放區方式,不受進程回收和 ASP.NET 應用程式故障的影響。該服務在 ASPNET 本地帳戶下運行,但可以使用服務控制管理員 (Service Control Manager) 介面來配置它。
另一個應該介紹的可執行檔是 aspnet_regiis.exe,儘管嚴格來講,它並不屬於 ASP.NET 運行時結構。該公用程式可以用來配置環境,以在一台電腦上並存執行不同版本的 ASP.NET,還可用於維修 IIS 和 ASP.NET 損壞的配置。該公用程式的工作方式是更新儲存在 IIS 設定資料庫的根目錄和子目錄中的指令碼映射。指令碼映射是資源類型和 ASP.NET 模組之間的一種關聯關係。最後,還可以使用該工具來顯示已安裝的 ASP.NET 版本的狀態,執行其他配置操作,如授予對特定檔案夾的 NTFS 許可權、建立客戶指令碼目錄。
<processModel> 部分有兩個屬性可以影響 Web Garden 模型,它們是 webGarden 和 cpuMask。webGarden 屬性接受布爾值,表示是否使用了多個輔助進程(一個相關的 CPU 對應一個進程)。預設情況下,該屬性的值為 false。cpuMask 屬性儲存一個 DWORD 值,該值的二進位表示為能夠運行 ASP.NET 輔助進程的 CPU 提供了位屏蔽。其預設值為 -1 (0xFFFFFF),表示可以使用所有可用的 CPU。如果 webGarden 屬性為 false,則 cpuMask 屬性的內容將被忽略。cpuMask 屬性還為正在啟動並執行 aspnet_wp.exe 的副本數設定了上限。
常言道“閃光的不都是金子”,用在這裡很合適。Web Garden 模式使得多個輔助進程可以同時運行。但是,需要注意的是所有進程都會有自己的應用程式狀態、進程內工作階段狀態、ASP.NET 緩衝、待用資料以及運行應用程式所需的其他內容。啟用 Web Garden 模式之後,ASP.NET ISAPI 將根據 CPU 的數量儘可能多地啟動輔助進程,每個輔助進程都是下一進程的完整複製(每一進程都與相應的 CPU 密切相關)。為平衡工作負載,傳入的請求以單迴圈的方式在啟動並執行進程之間進行劃分。輔助進程就象在單一處理器中一樣被回收。請注意,ASP.NET 繼承了作業系統中所有的 CPU 使用限制,並且不包括實現限制的自訂語義。
COM 和 DCOM 安全性與 Microsoft? .NET Framework 有何關係?實際上,CLR 是作為 COM 物件提供的。更準確地說,CLR 本身不是由 COM 代碼構成的,但是指向 CLR 的介面卻是一個 COM 物件。因此,輔助進程載入 CLR 的方式與載入 COM 物件的方式相同。
// 將頁面內容呈現給 HTML
RenderControl(CreateHtmlTextWriter(Response.Output));
}
無論調用的資源類型如何,基於 HTTP 處理常式的模型是相同的。唯一隨資源類型變化而變化的元素是處理常式。HttpApplication 對象負責尋找應該使用哪種處理常式來處理請求。HttpApplication 對象還負責檢測對動態建立的、表示資源的程式集(如 .aspx 頁面或 .asmx Web 服務)所進行的更改。如果檢測到更改,應用程式物件將確保編譯並載入所請求的資源的最新來源。
臨時檔案和頁面程式集
要全面瞭解 ASP.NET HTTP 運行時,讓我們來分析一下當請求 ASP.NET 頁面時,檔案系統層所發生的變化。接下來,您將瞭解由 HTTP 管道的對象管理和監視的一組動態建立的臨時檔案。
雖然可以將頁面的核心代碼隔離在代碼背後的 C# 或 Microsoft? Visual Basic? .NET 類中,但可以將 Web 頁面編寫和部署為 .aspx 文字檔。對於要顯示為 URL 的頁面來說,.aspx 檔案在應用程式的 Web 空間中必須始終可用。.aspx 檔案的實際內容將確定應用程式物件要載入的程式集(或多個程式集)。
按照設計,HttpApplication 對象將尋找一個根據請求的 ASPX 檔案命名的類。如果頁面命名為 sample.aspx,則要載入的相應的類名為 ASP.sample_aspx。應用程式物件在 Web 應用程式的所有組件檔夾中尋找這樣的類,這些檔案夾包括全域組件快取 (GAC)、Bin 子檔案夾和 Temporary ASP.NET Files 檔案夾。如果未找到這樣的類,HTTP 結構將分析 .aspx 檔案的原始碼,建立一個 C# 或 Visual Basic .NET 類(具體建立哪種類,取決於 .aspx 頁面上設定的語言),同時對其進行編譯。新建立的程式集的名稱是隨機產生的,位於特定於應用程式的子檔案夾中,路徑如下所示: C:WINDOWSMicrosoft.NETFrameworkv1.1.4322Temporary ASP.NET Files。
子檔案夾 v1.1.4322 特定於 ASP.NET 1.1。如果您使用的是 ASP.NET 1.0,子檔案夾的版本號碼會有所不同,即子檔案夾名為 v1.0.3705。再次訪問頁面時,程式集就已存在,不需要重新建立。但是,HttpApplication 對象是如何確定特定於頁面的程式集是否存在呢?它每次都要掃描大量檔案夾嗎?不,並不是這樣。
應用程式物件只查看 Temporary ASP.NET Files 檔案夾中某個特殊檔案夾的內容。具體路徑(特定於應用程式的路徑)由 HttpRuntime.CodegenDir 屬性返回。如果是第一次訪問 .aspx 檔案(即還未建立頁面程式集),則該檔案夾中就不存在以 ASPX 頁面名稱開頭的 XML 檔案。例如,具有動態程式集的 sample.aspx 頁面應有如下的條目:
sample.aspx.XXXXX.xml
XXXXX 預留位置是一種散列代碼。通過讀取該 XML 檔案的內容,應用程式物件就可以瞭解要載入的程式集的名稱以及要在其中擷取的類。以下程式碼片段是這種 Helper 檔案的典型內容。包含 ASP.sample_aspx 類的程式集的名稱是 mvxvx8xr。
ASP.NET 應用程式有兩大特徵:進程模型和頁面物件模型。ASP.NET 提前使用了 IIS 6.0 的一些功能,而 IIS 6.0 則是 Windows Server 2003 中提供的全新的、開創性的 Microsoft Web 資訊服務。尤其值得一提的是,在獨立的輔助進程中啟動並執行 ASP.NET 應用程式,其行為與 IIS 6 中的所有應用程式相同。而且,儘管會出現運行時異常、記憶體泄露或程式錯誤,ASP.NET 運行時仍能自動回收輔助進程以保證實現卓越的效能。這種功能已成為 IIS 6.0 的系統功能。
在本文中,我概括介紹了預設的 ASP.NET 進程模型的基礎知識,以及 IIS 級代碼(ASP.NET ISAPI 擴充)和輔助進程之間的互動。同時,還介紹了與 IIS 6 進程模型之間的最新區別。