原文地址:ASP.NET Internals – IIS and the Process Model
2007.05.03
Simone Busoli
ASP.NET是開發Web應用和組建的漂亮的架構,但是由於它的擴充,對絕大部分人,理解它的每一個細節顯得有點困難。儘管有很多書籍和網路文章,我總是覺得缺乏足夠的資訊來瞭解它的基礎架構,例如理解它的工作原理和高層次的設計取捨的一些必要的基本資料。這一系列文章中,我將描述Web請求的生命週期,從Web請求的最初階段開始,然後被伺服器接受,經過處理進入ASP.NET管道,在管道的終端產生Web響應的輸出。
介紹
微軟的Active Server Pages,即ASP,自1996年首次發布以來,為Web開發人員構建Web應用提供了一個豐富、複雜的架構。過去的幾年它的基礎架構發展的如此迅速,成為目前大家瞭解的ASP.NET,已經不再象它的前身。ASP.NET是構建Web應用的架構,就是說應用程式運行在Web上,客戶-伺服器端模式表現為瀏覽器向Web伺服器發送各種資源的請求。象CGI、PHP、JSP、ASP等動態伺服器端資源產生技術出現以前,所有Web伺服器必須接受用戶端靜態資源請求,將其發送給要求者。隨著動態技術的發展,Web伺服器開始承擔更多的職責,因為它們必須採取一些方式在伺服器端產生動態資源,將結果返回給用戶端,這已經是一項不同於以前的任務。
從菜鳥的角度來看,用戶端和伺服器端的互動很簡單,就是出現了使用HTTP(超文字傳輸通訊協定 (HTTP))的Web通訊。HTTP是一種依賴TCP、IP,在異構網路,即全球資訊網的兩個串連節點間傳輸資料的應用程式層協議。
每一種動態伺服器端技術都完全瞭解特定的Web伺服器實現,ASP.NET跟微軟的網際網路資訊服務器,即IIS緊密結合在一起。
不同的伺服器使用不同的方法產生動態資源,我們需要檢驗的是,IIS怎樣在伺服器上處理某個請求的路徑,將結果返回給用戶端。
IIS和ISAPI擴充
前面提到,靜態資源不需要伺服器處理,一旦接收到靜態資源請求,伺服器只需要從檔案系統擷取它的內容,按照HTTP協議向用戶端發送內容的位元組流。靜態資源可以是圖片、指令檔、css樣式表,或者html頁面。很明顯伺服器需要知道怎樣區別靜態和動態資源,因為後者需要經過某些處理,而不是直接將其發送給用戶端。這就是ISAPI出現的原因,ISAPI表示網際網路應用程式介面(Internet Server Application Programming Interface)。ISAPI擴充是使用Win32 .dll實現的模組,IIS使用它處理特定的資源。ISAPI擴充和檔案之間的映射通過IIS外掛程式配置,儲存在IIS中繼資料中。每一個檔案擴充可以和特定的ISAPI擴充關聯,就是說,當這種檔案的請求到達後,IIS將它交給相應的ISAPI擴充,認為它能夠處理。
圖1:在IIS 5.0中配置ISAPI擴充映射
很明顯ISAPI需要實現一個公用介面,IIS能夠使用詳細描述請求的資料進行調用,產生響應。
1的示範,.asp擴充被映射到asp.dll的ISAPI擴充。對於ASP頁面,這個組建負責處理所有的請求任務,產生輸出,包括收集請求資訊,通過Request、Response以及其它公用ASP內建對象將這些資訊傳遞給ASP頁面,解析執行ASP頁面,返回結果HTML。
實際上與CGI這樣的技術相比,這是一個極大的改進,但ASP.NET採取了更進一步的做法,引入抽象方法,避免開發人員必須關注這個過程中到底發生了什麼。
安裝完後,ASP.NET配置IIS,將特定的ASP.NET檔案請求重新導向到一個叫做aspnet_isapi.dll的ISAPI擴充。這個ISAPI擴充的處理跟之前的asp.dll擴充有點不一樣,asp.dll擴充只是負責解析和執行請求的ASP頁面。普通ISAPI模組處理請求的步驟完全被IIS隱藏,因此為了處理請求,ISAPI擴充可以採用不同的模式。
表1:aspnet_isapi.dll的IIS應用程式對應
副檔名 |
資源類型 |
.asax |
ASP.NET application files. Usually global.asax. |
.ascx |
ASP.NET user control files. |
.ashx |
HTTP handlers, the managed counterpart of ISAPI extensions. |
.asmx |
ASP.NET web services. |
.aspx |
ASP.NET web pages. |
.axd |
ASP.NET internal HTTP handlers. |
除了表1中的檔案擴充列表,ASP.NET ISAPI擴充也管理其它一些不支援瀏覽器請求的檔案擴充,例如Visual Studio工程檔案、原始碼和設定檔等。
ASP.NET處理模型
目前為止我們已經瞭解,IIS接收到ASP.NET檔案請求時,將其傳給aspnet_isapi.dll這個ASP.NET相關處理的主進入點。實際上ISAPI擴充怎樣進行處理,依賴於作業系統的IIS版本,不同版本的處理模型可能很不一樣。處理模型指ASP.NET運行時為了處理請求、產生響應而進行的操作序列。
當運行在IIS 5.x時,所有ASP.NET相關的請求被ISAPI擴充分發到一個叫做aspnet_wp.exe的外部背景工作處理序。運行在IIS進程inetinfo.exe中的ASP.NET ISAPI擴充將控制轉給aspnet_wp.exe,並傳遞請求相關的所有資訊。它們之間的通訊通過具名管道進行,即眾所周知的IPC(進程間通訊Inter Process Communication)機制。ASP.NET背景工作處理序與ISAPI擴充一起,執行一定數量的任務,它們是ASP.NET請求背後處理的主要承擔者。介紹一下後面會討論的一個主題,注意對應於IIS上不同虛擬目錄的每一個web應用程式,都是在同一個進程的上下文中執行的,即ASP.NET背景工作處理序。為了在執行內容中提供隔離,ASP.NET模型引入了應用程式定義域的概念,簡寫為AppDomain。它們可以看作是輕量級的進程,更多的討論在後面。
另一方面如果運行在IIS 6,不會使用aspnet_wp.exe,而是另外一個叫做w3wp.exe的進程。另外,inetinfo.exe不再向ISAPI傳遞HTTP請求,但它仍然處理其他請求協議。儘管IIS 6能夠以相容模式運行,類比前一個版本IIS的行為,但與IIS 5相比處理模型上很多細節改變了。一個大的改進是,與運行在IIS 5上的處理模型相比,到達的請求將在較低的核心層級處理,然後傳遞給適當的ISAPI擴充。這避免了進程間通訊技術,從效能和資源消耗角度來看,進程間通訊是一個昂貴的操作。我們在下面的章節中深入探討這個。
IIS 5.0處理模型
這是Windows 2000和XP機器上預設的處理模型。前面提到它位於IIS inetinfo.exe進程中,預設監聽TCP 80連接埠接收HTTP請求,將請求排列到一個隊列中,等待接受處理。如果請求是ASP.NET類型,這個處理被委託給ASP.NET ISAPI擴充,即aspnet_isapi.dll。接下來通過具名管道與ASP.NET背景工作處理序aspnet_wp.exe通訊,最後由背景工作處理序將請求交給ASP.NET HTTP運行時環境。圖2以圖形方式展現這個處理過程。
圖2:IIS 5.0處理模型
圖2中出現了一個我們還沒有提到過的額外元素,ASP.NET HTTP運行時環境。這不是本文的主題,會在後續的文章中詳細解釋,但為了本文的討論,可以把HTTP運行時環境看作一個黑箱,ASP.NET相關的處理在這兒完成,所有Managed 程式碼位於這,開發人員可以在這進行處理,從直接的HttpRuntime到HttpHandler等,在這處理請求,產生響應。這也被稱為ASP.NET管道,或者HTTP運行時管道。
這個處理模型中有意思的一點是,所有的請求一旦被ISAPI擴充處理,就被傳給ASP.NET背景工作處理序。同一時間只有一個ASP.NET進程執行個體是活動狀態,不過有一個例外,後面會討論。因此運行在IIS中的所有ASP.NET web應用程式實際上也是運行在背景工作處理序上的,然而這並不意味著所有的應用程式運行在相同的上下文中,共用所有的資料。前面提到,ASP.NET引入了AppDomain的概念,它其實是一種託管的輕量級進程,提供隔離和安全邊界。每個IIS虛擬目錄在獨立的AppDomain中執行,當屬於這個應用的任何一個資源在第一次請求時,這個AppDomain被自動載入到背景工作處理序中。AppDomain被載入之後,就是說所有用於處理這個請求所需的程式集被載入到AppDomain中,然後控制權被傳給ASP.NET管道進行實際的處理。多個AppDomain可以運行在同一個進程中,同一個AppDomain的請求可以用多個線程來處理,然而線程並不屬於AppDomain,它可以服務於不同AppDomain的請求,但在給定的時間一個線程只會屬於一個AppDomain。
出於效能原因,背景工作處理序可能會依據某些條件進行回收,可以從位於C:\windows\microsoft.net\Framework\[framework version]\CONFIG目錄中的machine.config檔案看到這些描述性的條件,包括進程存留時間、正在處理以及隊列中的請求數、空閑時間以及記憶體消耗。一旦達到這些參數中的某個預設值,ISAPI擴充為背景工作處理序建立一個新的執行個體,用它繼續處理請求。只有在這個時候多個背景工作處理序並發運行,實際上老的進程執行個體並沒有被結束掉,允許它處理剩餘的請求。
IIS 6.0處理模型
IIS 6處理模型是運行Windows 2003 Server作業系統的機器上預設的模型,它在IIS 5處理模型的基礎上引入了幾個改進,最大的改變之一是引入了應用程式集區的概念。在IIS 5.x上,所有的web應用程式,即所有的AppDomain運行在ASP.NET背景工作處理序中,為了實現更好的安全邊界粒度以及定製能力,IIS 6處理模式允許應用程式運行在不同的背景工作處理序中,即w3wp.exe。每個應用程式集區可以包含多個AppDomain,運行在獨立的背景工作處理序中,換句話說就是從單個進程運行所有的應用程式切換到每個背景工作處理序運行一個應用程式集區。這個模式也叫做背景工作處理序隔離模式(worker process isolation mode)。
與之前的模式相比,另一個大的改變是IIS監聽請求的方式。IIS 5模式中,由IIS進程inetinfo.exe來監聽特定的TCP連接埠,接收HTTP請求,在IIS 6架構中,通過一個叫做http.sys的核心驅動,在核心層級而不是之前的使用者模式下處理和排隊請求,這種方式比老的模式有一些優點,叫做核心級請求隊列(kernel-level request queuing)。
圖3:IIS 6.0處理模型
圖3示範了使用IIS 6模式處理請求的主要組建。請求到達後,核心級的裝置驅動http.sys將其傳遞到正確的應用程式集區隊列中,每個隊列屬於特定的應用程式集區,也就是說屬於特定的背景工作處理序,接下來背景工作處理序從隊列中接收請求。這種方式極大的降低了IIS 5模式中引入的具名管道的開銷,因為不再需要進程間通訊,請求直接從核心級驅動傳遞給背景工作處理序,這樣有很多的優點,例如可靠性。因為運行在核心模式中,請求分發不受使用者模式,即背景工作處理序中宕機和故障的影響,因此即使背景工作處理序宕機了,系統仍然能夠接收請求,重起宕機的進程。
背景工作處理序負責載入ASP.NET ISAPI擴充,它依次載入CLR,將所有的工作委託給HTTP運行時。
w3wp.exe背景工作處理序不同於IIS 5模式中的aspnet_wp.exe進程,跟ASP.NET不相關,它用於處理任何類型的請求,然後背景工作處理序根據它需要處理的資源類型決定載入哪些ISAPI模組。
出於簡化目的在圖3中有一個細節沒有標出來,到達的請求通過IIS 6中載入的一個叫做Web管理服務(WAS)的模組,從應用程式集區隊列傳遞給正確的背景工作處理序。這個模組負責從IIS中繼資料讀取背景工作處理序與web應用程式的邦定資訊,將請求傳遞給正確的背景工作處理序。
引用
Simone Busoli - ASP.NET
Internals - The bridge between ISAPI and Application Domains
BrainBell.com – ASP.NET Application Fundamentals
Dino Esposito – Programming Microsoft ASP.NET 2.0 Core Reference
Dino Esposito – Programming Microsoft ASP.NET 2.0 Applications Advanced Topics
George Shepherd – IIS 6.0: New Features Improve Your Web Server's Performance,
Reliability, and Scalability
Fritz Onion – ASP.NET Pipeline: Use Threads and Build Asynchronous Handlers in
Your Server-Side Web Code
Tim Ewald and Keith Brown – HTTP Pipelines: Securely Implement Request Processing, Filtering,
and Content Redirection with HTTP Pipelines in ASP.NET