ASP.NET內(nèi)幕 - IIS處理模型
 

 

 

微軟的Active ServerPages,即ASP,自1996年首次發(fā)布以來,為Web開發(fā)者構(gòu)建Web應(yīng)用提供了一個豐富、復(fù)雜的框架。過去的幾年它的基礎(chǔ)架構(gòu)發(fā)展的如此迅速,成為目前大家了解的ASP.NET,已經(jīng)不再象它的前身。ASP.NET是構(gòu)建Web應(yīng)用的框架,就是說應(yīng)用程序運(yùn)行在Web上,客戶-服務(wù)器端模式表現(xiàn)為瀏覽器向Web服務(wù)器發(fā)送各種資源的請求。象CGI、PHP、JSP、ASP等動態(tài)服務(wù)器端資源生成技術(shù)出現(xiàn)以前,所有Web服務(wù)器必須接受客戶端靜態(tài)資源請求,將其發(fā)送給請求者。隨著動態(tài)技術(shù)的發(fā)展,Web服務(wù)器開始承擔(dān)更多的職責(zé),因?yàn)樗鼈儽仨毑扇∫恍┓绞皆诜?wù)器端生成動態(tài)資源,將結(jié)果返回給客戶端,這已經(jīng)是一項(xiàng)不同于以前的任務(wù)。

從菜鳥的角度來看,客戶端和服務(wù)器端的交互很簡單,就是出現(xiàn)了使用HTTP(超文本傳輸協(xié)議)的Web通訊。HTTP是一種依賴TCP、IP,在異構(gòu)網(wǎng)絡(luò),即萬維網(wǎng)的兩個連接節(jié)點(diǎn)間傳輸數(shù)據(jù)的應(yīng)用層協(xié)議。

每一種動態(tài)服務(wù)器端技術(shù)都完全了解特定的Web服務(wù)器實(shí)現(xiàn),ASP.NET跟微軟的因特網(wǎng)信息服務(wù)器,即IIS緊密結(jié)合在一起。

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

IIS和ISAPI擴(kuò)展

前面提到,靜態(tài)資源不需要服務(wù)器處理,一旦接收到靜態(tài)資源請求,服務(wù)器只需要從文件系統(tǒng)獲取它的內(nèi)容,按照HTTP協(xié)議向客戶端發(fā)送內(nèi)容的字節(jié)流。靜態(tài)資源可以是圖片、腳本文件、css樣式表,或者h(yuǎn)tml頁面。很明顯服務(wù)器需要知道怎樣區(qū)別靜態(tài)和動態(tài)資源,因?yàn)楹笳咝枰?jīng)過某些處理,而不是直接將其發(fā)送給客戶端。這就是ISAPI出現(xiàn)的原因,ISAPI表示因特網(wǎng)應(yīng)用程序接口(Internet Server ApplicationProgramming Interface)。ISAPI擴(kuò)展是使用Win32.dll實(shí)現(xiàn)的模塊,IIS使用它處理特定的資源。ISAPI擴(kuò)展和文件之間的映射通過IIS插件配置,存儲在IIS元數(shù)據(jù)中。每一個文件擴(kuò)展可以和特定的ISAPI擴(kuò)展關(guān)聯(lián),就是說,當(dāng)這種文件的請求到達(dá)后,IIS將它交給相應(yīng)的ISAPI擴(kuò)展,認(rèn)為它能夠處理。

圖1:在IIS 5.0中配置ISAPI擴(kuò)展映射

很明顯ISAPI需要實(shí)現(xiàn)一個公共接口,IIS能夠使用詳細(xì)描述請求的數(shù)據(jù)進(jìn)行調(diào)用,生成響應(yīng)。

如圖1的演示,.asp擴(kuò)展被映射到asp.dll的ISAPI擴(kuò)展。對于ASP頁面,這個組建負(fù)責(zé)處理所有的請求任務(wù),生成輸出,包括收集請求信息,通過 Request、Response以及其它公共ASP內(nèi)置對象將這些信息傳遞給ASP頁面,解析執(zhí)行ASP頁面,返回結(jié)果HTML。

實(shí)際上與CGI這樣的技術(shù)相比,這是一個極大的改進(jìn),但ASP.NET采取了更進(jìn)一步的做法,引入抽象方法,避免開發(fā)者必須關(guān)注這個過程中到底發(fā)生了什么。

安裝完后,ASP.NET配置IIS,將特定的ASP.NET文件請求重定向到一個叫做aspnet_isapi.dll的ISAPI擴(kuò)展。這個ISAPI 擴(kuò)展的處理跟之前的asp.dll擴(kuò)展有點(diǎn)不一樣,asp.dll擴(kuò)展只是負(fù)責(zé)解析和執(zhí)行請求的ASP頁面。普通ISAPI模塊處理請求的步驟完全被 IIS隱藏,因此為了處理請求,ISAPI擴(kuò)展可以采用不同的模式。

表1:aspnet_isapi.dll的IIS應(yīng)用程序映射

擴(kuò)展名 資源類型
.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中的文件擴(kuò)展列表,ASP.NET ISAPI擴(kuò)展也管理其它一些不支持瀏覽器請求的文件擴(kuò)展,例如Visual Studio工程文件、源代碼和配置文件等。

ASP.NET處理模型

目前為止我們已經(jīng)了解,IIS接收到ASP.NET文件請求時,將其傳給aspnet_isapi.dll這個ASP.NET相關(guān)處理的主入口點(diǎn)。實(shí)際上 ISAPI擴(kuò)展怎樣進(jìn)行處理,依賴于操作系統(tǒng)的IIS版本,不同版本的處理模型可能很不一樣。處理模型指ASP.NET運(yùn)行時為了處理請求、生成響應(yīng)而進(jìn)行的操作序列。

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

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

IIS 5.0處理模型

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

圖2:IIS 5.0處理模型

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

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

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

IIS 6.0處理模型

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

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

圖3:IIS 6.0處理模型

圖 3演示了使用IIS6模式處理請求的主要組建。請求到達(dá)后,內(nèi)核級的設(shè)備驅(qū)動http.sys將其傳遞到正確的應(yīng)用程序池隊(duì)列中,每個隊(duì)列屬于特定的應(yīng)用程序池,也就是說屬于特定的工作進(jìn)程,接下來工作進(jìn)程從隊(duì)列中接收請求。這種方式極大的降低了IIS5模式中引入的命名管道的開銷,因?yàn)椴辉傩枰M(jìn)程間通訊,請求直接從內(nèi)核級驅(qū)動傳遞給工作進(jìn)程,這樣有很多的優(yōu)點(diǎn),例如可靠性。因?yàn)檫\(yùn)行在內(nèi)核模式中,請求分發(fā)不受用戶模式,即工作進(jìn)程中宕機(jī)和故障的影響,因此即使工作進(jìn)程宕機(jī)了,系統(tǒng)仍然能夠接收請求,重起宕機(jī)的進(jìn)程。

工作進(jìn)程負(fù)責(zé)加載ASP.NET ISAPI擴(kuò)展,它依次加載CLR,將所有的工作委托給HTTP運(yùn)行時。

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

出于簡化目的在圖3中有一個細(xì)節(jié)沒有標(biāo)出來,到達(dá)的請求通過IIS 6中加載的一個叫做Web管理服務(wù)(WAS)的模塊,從應(yīng)用程序池隊(duì)列傳遞給正確的工作進(jìn)程。這個模塊負(fù)責(zé)從IIS元數(shù)據(jù)讀取工作進(jìn)程與web應(yīng)用程序的邦定信息,將請求傳遞給正確的工作進(jìn)程。