ASP.NET內幕 - IIS處理模型
 

 

 

微軟的Active ServerPages,即ASP,自1996年首次發布以來,為Web開發者構建Web應用提供了一個豐富、復雜的框架。過去的幾年它的基礎架構發展的如此迅速,成為目前大家了解的ASP.NET,已經不再象它的前身。ASP.NET是構建Web應用的框架,就是說應用程序運行在Web上,客戶-服務器端模式表現為瀏覽器向Web服務器發送各種資源的請求。象CGI、PHP、JSP、ASP等動態服務器端資源生成技術出現以前,所有Web服務器必須接受客戶端靜態資源請求,將其發送給請求者。隨著動態技術的發展,Web服務器開始承擔更多的職責,因為它們必須采取一些方式在服務器端生成動態資源,將結果返回給客戶端,這已經是一項不同于以前的任務。

從菜鳥的角度來看,客戶端和服務器端的交互很簡單,就是出現了使用HTTP(超文本傳輸協議)的Web通訊。HTTP是一種依賴TCP、IP,在異構網絡,即萬維網的兩個連接節點間傳輸數據的應用層協議。

每一種動態服務器端技術都完全了解特定的Web服務器實現,ASP.NET跟微軟的因特網信息服務器,即IIS緊密結合在一起。

不同的服務器使用不同的方法生成動態資源,我們需要檢驗的是,IIS怎樣在服務器上處理某個請求的路徑,將結果返回給客戶端。

IIS和ISAPI擴展

前面提到,靜態資源不需要服務器處理,一旦接收到靜態資源請求,服務器只需要從文件系統獲取它的內容,按照HTTP協議向客戶端發送內容的字節流。靜態資源可以是圖片、腳本文件、css樣式表,或者html頁面。很明顯服務器需要知道怎樣區別靜態和動態資源,因為后者需要經過某些處理,而不是直接將其發送給客戶端。這就是ISAPI出現的原因,ISAPI表示因特網應用程序接口(Internet Server ApplicationProgramming 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運行時為了處理請求、生成響應而進行的操作序列。

當運行在IIS5.x時,所有ASP.NET相關的請求被ISAPI擴展分發到一個叫做aspnet_wp.exe的外部工作進程。運行在IIS進程inetinfo.exe中的ASP.NETISAPI擴展將控制轉給aspnet_wp.exe,并傳遞請求相關的所有信息。它們之間的通訊通過命名管道進行,即眾所周知的IPC(進程間通訊Inter ProcessCommunication)機制。ASP.NET工作進程與ISAPI擴展一起,執行一定數量的任務,它們是ASP.NET請求背后處理的主要承擔者。介紹一下后面會討論的一個主題,注意對應于IIS上不同虛擬目錄的每一個web應用程序,都是在同一個進程的上下文中執行的,即 ASP.NET工作進程。為了在執行上下文中提供隔離,ASP.NET模型引入了應用程序域的概念,簡寫為AppDomain。它們可以看作是輕量級的進程,更多的討論在后面。

另一方面如果運行在IIS6,不會使用aspnet_wp.exe,而是另外一個叫做w3wp.exe的進程。另外,inetinfo.exe不再向ISAPI傳遞HTTP請求,但它仍然處理其他請求協議。盡管IIS 6能夠以兼容模式運行,模擬前一個版本IIS的行為,但與IIS5相比處理模型上很多細節改變了。一個大的改進是,與運行在IIS5上的處理模型相比,到達的請求將在較低的內核層級處理,然后傳遞給適當的ISAPI擴展。這避免了進程間通訊技術,從性能和資源消耗角度來看,進程間通訊是一個昂貴的操作。我們在下面的章節中深入探討這個。

IIS 5.0處理模型

這是Windows 2000和XP機器上默認的處理模型。前面提到它位于IIS inetinfo.exe進程中,默認監聽TCP80端口接收HTTP請求,將請求排列到一個隊列中,等待接受處理。如果請求是ASP.NET類型,這個處理被委托給ASP.NETISAPI擴展,即aspnet_isapi.dll。接下來通過命名管道與ASP.NET工作進程 aspnet_wp.exe通訊,最后由工作進程將請求交給ASP.NET HTTP運行時環境。圖2以圖形方式展現這個處理過程。

圖2:IIS 5.0處理模型

圖 2中出現了一個我們還沒有提到過的額外元素,ASP.NETHTTP運行時環境。這不是本文的主題,會在后續的文章中詳細解釋,但為了本文的討論,可以把 HTTP運行時環境看作一個黑箱,ASP.NET相關的處理在這兒完成,所有托管代碼位于這,開發者可以在這進行處理,從直接的HttpRuntime到 HttpHandler等,在這處理請求,生成響應。這也被稱為ASP.NET管道,或者HTTP運行時管道。

這個處理模型中有意思的一點是,所有的請求一旦被ISAPI擴展處理,就被傳給ASP.NET工作進程。同一時間只有一個ASP.NET進程實例是活動狀態,不過有一個例外,后面會討論。因此運行在IIS中的所有ASP.NETweb應用程序實際上也是運行在工作進程上的,然而這并不意味著所有的應用程序運行在相同的上下文中,共享所有的數據。前面提到,ASP.NET引入了AppDomain的概念,它其實是一種托管的輕量級進程,提供隔離和安全邊界。每個IIS虛擬目錄在獨立的AppDomain中執行,當屬于這個應用的任何一個資源在第一次請求時,這個AppDomain被自動加載到工作進程中。AppDomain被加載之后,就是說所有用于處理這個請求所需的程序集被加載到AppDomain中,然后控制權被傳給ASP.NET管道進行實際的處理。多個AppDomain 可以運行在同一個進程中,同一個AppDomain的請求可以用多個線程來處理,然而線程并不屬于AppDomain,它可以服務于不同 AppDomain的請求,但在給定的時間一個線程只會屬于一個AppDomain。

出于性能原因,工作進程可能會依據某些條件進行回收,可以從位于C:\windows\microsoft.net\Framework\[frameworkversion]\CONFIG目錄中的 machine.config文件看到這些描述性的條件,包括進程生存時間、正在處理以及隊列中的請求數、空閑時間以及內存消耗。一旦達到這些參數中的某個預設值,ISAPI擴展為工作進程創建一個新的實例,用它繼續處理請求。只有在這個時候多個工作進程并發運行,實際上老的進程實例并沒有被結束掉,允許它處理剩余的請求。

IIS 6.0處理模型

IIS 6處理模型是運行Windows 2003 Server操作系統的機器上默認的模型,它在IIS5處理模型的基礎上引入了幾個改進,最大的改變之一是引入了應用程序池的概念。在IIS5.x上,所有的web應用程序,即所有的AppDomain運行在ASP.NET工作進程中,為了實現更好的安全邊界粒度以及定制能力,IIS6處理模式允許應用程序運行在不同的工作進程中,即w3wp.exe。每個應用程序池可以包含多個AppDomain,運行在獨立的工作進程中,換句話說就是從單個進程運行所有的應用程序切換到每個工作進程運行一個應用程序池。這個模式也叫做工作進程隔離模式(worker processisolation mode)。

與之前的模式相比,另一個大的改變是IIS監聽請求的方式。IIS5模式中,由IIS進程inetinfo.exe來監聽特定的TCP端口,接收HTTP請求,在IIS6架構中,通過一個叫做http.sys的內核驅動,在內核層級而不是之前的用戶模式下處理和排隊請求,這種方式比老的模式有一些優點,叫做內核級請求隊列(kernel-level request queuing)。

圖3:IIS 6.0處理模型

圖 3演示了使用IIS6模式處理請求的主要組建。請求到達后,內核級的設備驅動http.sys將其傳遞到正確的應用程序池隊列中,每個隊列屬于特定的應用程序池,也就是說屬于特定的工作進程,接下來工作進程從隊列中接收請求。這種方式極大的降低了IIS5模式中引入的命名管道的開銷,因為不再需要進程間通訊,請求直接從內核級驅動傳遞給工作進程,這樣有很多的優點,例如可靠性。因為運行在內核模式中,請求分發不受用戶模式,即工作進程中宕機和故障的影響,因此即使工作進程宕機了,系統仍然能夠接收請求,重起宕機的進程。

工作進程負責加載ASP.NET ISAPI擴展,它依次加載CLR,將所有的工作委托給HTTP運行時。

w3wp.exe工作進程不同于IIS 5模式中的aspnet_wp.exe進程,跟ASP.NET不相關,它用于處理任何類型的請求,然后工作進程根據它需要處理的資源類型決定加載哪些ISAPI模塊。

出于簡化目的在圖3中有一個細節沒有標出來,到達的請求通過IIS 6中加載的一個叫做Web管理服務(WAS)的模塊,從應用程序池隊列傳遞給正確的工作進程。這個模塊負責從IIS元數據讀取工作進程與web應用程序的邦定信息,將請求傳遞給正確的工作進程。