微软的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应用程序的邦定信息,将请求传递给正确的工作进程。