ASP.NET站点频繁出现Server Too Busy错误,具体表现为页面响应慢、经常出现Server Too Busy异常;但实际上服务器的资源消耗却很低,CPU使用只有10%左右,非常奇怪。
该站点运行环境为Windows 2000,IIS5.0,.NET Framework 1.1,站点压力约为每秒10个连接,峰值时约为30。
从网上查找相关资料后,从表现出的情况来看(响应慢,抛出Server Too Busy异常),初步判断为同时连接过多引起的线程阻塞引起。修改web.config中的httpRuntime配置节中的appRequestQueueLimit参数后,Server Too Busy 的错误得到解决。此参数默认从machine.config中继承,默认值为100,改为1000后Server Too Busy的错误不再出现。
虽然服务器忙的错误解决了,但是站点响应还是很慢,有时候要等上5—10秒才能打开页面。分析原因应该是同时请求过多,而IIS工作线程不足的原因引起,修改machine.config中processModel配置节maxWorkerThreads参数为200后站点响应速度慢的问题得到解决。此参数默认值为20,可根据服务器硬件配置于压力大小适当调整。
分析原因,是因为站点程序中使用了HttpWebRequest请求外部服务器的页面,而这个操作是相当耗时的(外部服务器响应慢是主要原因)。当访问者的请求到达ASP.NET工作进程后,ASP.NET首先会检查是否有空余的工作线程(WorkerThread),如果有的话,就交给一个空闲的工作线程去处理,如果没有空闲的工作线程,那么这个请求就会被放到请求队列(RequestQueue)中,这个时候的表现就是响应很慢。当访问量过大导致请求队列也满了的时候,ASP.NET就会抛出Server Too Busy异常了。在.NET 1.1中,默认的工作线程和请求队列分别为20和100,当运行的代码比较费时而访问量又较大的时候,这两个默认值显然就太小了。(现在的服务器硬件便宜了,一般PC服务器的吞吐量都应该远超过这个数)。这两个值可以根据服务器压力大小来进行合理配置。以调整站点吞吐量。
httpRuntime代码放在web.config哪里?深度了解httpRuntime
httpRuntime
是配置asp.net http运行时设置,以确定如何处理对asp.net应用程序的请求。
不过,httpRuntime
代码需要手动添加到web.config
里,但具体添加到哪个节点区块中,大家不一定知道。如果放置的位置不对,那么设置就不正确,严重点还可能影响到web.config
这个文件里的其他设置。
本文介绍httpRuntime
代码如何正确添加到web.config
里,并提供一个完整的web.config
配置代码给大家参考。
httpRuntime代码放在web.config哪里?
正确的添加方法是,在web.config
中的<system.web></system.web>
内添加httpRuntime
代码。
例如:
- <system.web>
- <httpRuntime
- executionTimeout="600"
- maxRequestLength="951200"
- useFullyQualifiedRedirectUrl="true"
- minFreeThreads="8"
- minLocalRequestFreeThreads="4"
- appRequestQueueLimit="100"
- enableVersionHeader="true"
- />
- </system.web>
实际应用中,<system.web></system.web>
里还有其他的设置代码,下面是一个完整的web.config
配置代码:
- <?xml version="1.0" encoding="UTF-8"?>
- <configuration>
- <connectionStrings>
- <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
- </connectionStrings>
- <system.web>
- <compilation debug="true" targetFramework="4.0" />
- <authentication mode="Forms">
- <forms loginUrl="~/Account/Login.aspx" timeout="2880" />
- </authentication>
- <profile>
- <providers>
- <clear />
- <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
- </providers>
- </profile>
- <roleManager enabled="false">
- <providers>
- <clear />
- <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
- <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
- </providers>
- </roleManager>
- <httpRuntime
- executionTimeout="600"
- maxRequestLength="951200"
- useFullyQualifiedRedirectUrl="true"
- minFreeThreads="8"
- minLocalRequestFreeThreads="4"
- appRequestQueueLimit="100"
- enableVersionHeader="true"
- />
- </system.web>
- </configuration>
httpRuntime代码解释:
通过上面的配置说明, 下面是在Web.Config
里节点的设置:
IIS 所收到的对某 Microsoft ASP.NET 页面的每个请求都被移交给 ASP.NET HTTP 管线。HTTP 管线由一系列托管对象组成,这些对象按顺序处理该请求,并完成从 URL 到普通 HTML 文本的转换。HTTP 管线的入口点是 HttpRuntime
类。ASP.NET 基础结构为辅助进程中所承载的每个 AppDomain
创建此类的一个实例请注意,该辅助进程为当前正在运行的每个 ASP.NET 应用程序维护一个不同的 AppDomain
。
要激活 HTTP 管道,可以创建一个 HttpRuntime
类的新实例,然后调用其 ProcessRequest
方法。
一个完整的页面请求会包括下面的流程:
首先被WWW服务器截获(inetinfo.exe进程), 该进程首先判断页面后缀, 然后根据IIS中配置决定调用具体的扩展程序。aspx就会调用aspnet_isapi.dll,然后由aspnet_isapi.dll发送给w3wp.exe(iis 工作者进程,IIS6.0中叫做 w3wq.exe,IIS5.0中叫做 aspnet_wp.exe)。
接下来在w3wp.exe调用.NET类库进行具体处理,顺序如下:ISAPIRuntim
, HttpRuntime
, HttpApplicationFactory
, HttpApplication
, HttpModule
, HttpHandlerFactory
, HttpHandler
。
ISAPIRuntime:主要作用是调用一些非托管代码生成HttpWorkerRequest
对象,HttpWorkerRequest
对象包含当前请求的所有信息,然后传递给HttpRuntime
。
HttpRuntime:根据HttpWorkerRequest
对象生成HttpContext
,HttpContext
包含request、response等属性, 再调用HttpApplicationFactory
来生成IHttpHandler
, 调用HttpApplication
对象执行请求。
HttpApplicationFactory:生成一个HttpApplication
对象。
HttpApplication:进行HttpModule
的初始化,HttpApplication
创建针对此Http请求的 HttpContext
对象。
HttpModule:当一个HTTP请求到达HttpModule
时,整个ASP.NET Framework系统还并没有对这个HTTP请求做任何处理,也就是说此时对于HTTP请求来讲,HttpModule
是一个HTTP请求的“必经之路”,所以可以在这个HTTP请求传递到真正的请求处理中心(HttpHandler
)之前附加一些需要的信息在这个HTTP请求信息之上,或者针对截获的这个HTTP请求信息作一些额外的工作,或者在某些情况下干脆终止满足一些条件的HTTP请求,从而可以起到一个Filter过滤器的作用。
HttpHandlerFactory:把用户request 转发到HttpHandlerFactory
,再由HttpHandlerFactory
实例化HttpHandler
对象来相应request。
HttpHandle:Http处理程序,处理页面请求 。
- executionTimeout:表示允许执行请求的最大时间限制,单位为秒。
- maxRequestLength:指示 ASP.NET 支持的最大文件上载大小。该限制可用于防止因用户将大量文件传递到该服务器而导致的拒绝服务攻击。指定的大小以 KB 为单位。默认值为 4096 KB (4 MB)。
- useFullyQualifiedRedirectUrl:表示指示客户端重定向是否是完全限定的(采用 "
http://server/path
" 格式,这是某些移动控件所必需的),或者指示是否代之以将相对重定向发送到客户端。如果为 True,则所有不是完全限定的重定向都将自动转换为完全限定的格式。false 是默认选项。 - minFreeThreads:表示指定允许执行新请求的自由线程的最小数目。ASP.NET 为要求附加线程来完成其处理的请求而使指定数目的线程保持自由状态。默认值为 8。
- minLocalRequestFreeThreads:表示ASP.NET 保持的允许执行新本地请求的自由线程的最小数目。该线程数目是为从本地主机传入的请求而保留的,以防某些请求在其处理期间发出对本地主机的子请求。这避免了可能的因递归重新进入 Web 服务器而导致的死锁。
- appRequestQueueLimit:表示ASP.NET 将为应用程序排队的请求的最大数目。当没有足够的自由线程来处理请求时,将对请求进行排队。当队列超出了该设置中指定的限制时,将通过“503 - 服务器太忙”错误信息拒绝传入的请求。
- enableVersionHeader:表示指定 ASP.NET 是否应输出版本标头。Microsoft Visual Studio 2005 使用该属性来确定当前使用的 ASP.NET 版本。对于生产环境,该属性不是必需的,可以禁用。
-
深度了解HttpRuntime
先介绍
HttpRuntime
的Web.config
里的配置: - <httpRuntime
- executionTimeout = "number"
- maxRequestLength = "number"
- requestLengthDiskThreshold = "number"
- useFullyQualifiedRedirectUrl = "[True|False]"
- minFreeThreads = "number"
- minLocalRequestFreeThreads = "number"
- appRequestQueueLimit = "number"
- enableKernelOutputCache = "[True|False]"
- enableVersionHeader = "[True|False]"
- apartmentThreading = "[True|False]"
- requireRootedSaveAsPath = "[True|False]"
- enable = "[True|False]"
- sendCacheControlHeader = "[True|False]"
- shutdownTimeout = "number"
- delayNotificationTimeout = "number"
- waitChangeNotification = "number"
- maxWaitChangeNotification = "number"
- enableHeaderChecking = "[True|False]"
- />
- <configuration>
- <system.web>
- <httpRuntime
- maxRequestLength="4000"
- enable = "True"
- requestLengthDiskThreshold="512
- useFullyQualifiedRedirectUrl="True"
- executionTimeout="45"
- versionHeader="1.1.4128"
- />
- <system.web>
- <configuration>