微軟的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)程。 |