asp.net

HTTP 错误 403.9 - 禁止访问:连接的用户过多?怎样解决这种问题?

2011-02-19

  情况:从   ASP.NET   页面调用   Web   服务时的性能破坏    
  我们在本专栏中讨论   Web   服务时,期望在各种情况下都可以享用   Web   服务。一个主要的情况是从中间层环境(如   ASP.NET   Web   页面)访问   Web   服务。为   MapPoint   .NET   Web   服务的用户提供支持的人员经常收到这样的问题,即用户在使用其   Web   服务时,对   MapPoint   .NET   的调用可能需要相当长的时间。这本身并不是什么问题,但某些其他因素可以使之成为比表面上要严重得多的大问题。  
  HTTP   双连接限制  
  HTTP   规范表明,一个   HTTP   客户端与任一服务器最多可以同时建立两个   TCP   连接。这可以防止单个浏览器在浏览某个页面(例如,具有   120   个嵌入的缩略图)时,由于连接请求过多而使服务器负载过重。此时,浏览器将仅创建   2   个连接,然后通过这两个管道开始发送   120   个   HTTP   请求,而不是创建   120   个   TCP   连接并通过每个连接来发送   HTTP   请求。对于中间层,此方法的问题在于,中间层可能会有   50   个同时请求连接的用户。如果不得不为每个用户进行一次   MapPoint   .NET   Web   服务调用,将会有   48   个用户等待两个管道中的一个空闲下来。  
  线程池限制  
  ASP.NET   处理传入的请求的方式是通过一个称为进程线程池的一组线程为其提供服务。正常情况下,请求传入后,池中某个空闲的线程将为其提供服务。这里的问题在于,进程线程池不会创建无数个线程来处理大量的请求。具有最大线程数限制是一件好事,因为如果我们无限地创建线程,计算机上的全部资源将只能用来管理这些线程了。通过限制所能创建的线程数,我们可以把线程管理的系统开销保持在一个可控的水平。如果某个请求传入时线程池中的所有线程都被占用,则该请求将排队等候,在忙线程完成任务后,空闲出来的线程才能处理新请求。此方法实际上比切换到某个新线程更有效,因为不需要在请求之间进行线程切换。但存在的问题是,如果线程的使用效率不高(尤其是在非常忙的   Web   服务器上),则等候的请求队列会变得很大。  
  考虑一下从   ASP.NET   页面进行   Web   服务调用的情况。如果进行同步调用,则正在运行的线程将被阻塞,直到   Web   服务调用完成为止。在调用期间,线程无法进行任何其他活动。它无法处理其他请求,只能等待。如果某个单处理器计算机上具有默认的工作线程数   20,则只需   20   个同时进行的请求即可用完全部线程,以后的请求必须排队等候。  
  该问题不仅限于   Web   服务  
  不仅调用   Web   服务的用户会遇到从   Web   页面进行调用时的拥堵且耗时较长的问题。进行任意数量的较长的调用都会遇到同样的问题,例如:SQL   Server™   请求、长文件的读取或写入、各种   Web   请求或访问某个并发资源(其中锁定会造成严重的延迟)。实际上,有许多使用   Web   服务的情况,其服务调用比较迅速,并不是什么问题。但您或许会理解,如果您想通过代理服务器调用   MapPoint   .NET   Web   服务,所使用的连接具有一定的延迟,同时相应的服务可能又要花费一些时间来处理请求,则您可能在各处位置都看到延迟的情况,并且如果站点很忙,便可能出现问题。  
  改善问题    
  该问题的某些方面可以通过对环境进行某些配置设置来改善。我们看一下可用于改善该问题的某些配置设置。  
  maxconnections  
  连接到   Web   资源的默认双连接限制可以通过一个名为   connectionManagement   的配置元素来控制。connectionManagement   设置允许您添加要让其采用非默认连接限制的站点的名称。可以将以下内容添加到典型的   Web.config   文件中,将您连接的所有服务器的连接限制默认值增加到   40。  
  <configuration>  
      <system.net>  
          <connectionManagement>  
              <add   address="*"   maxconnection="40"   />  
          </connectionManagement>  
      </system.net>  
   
      <system.web>  
            ...  
  应当注意的是,对本地计算机的连接数量从来都没有限制,因此,如果是连接到本地主机,则此设置无效。  
  maxWorkerThreads   和   minFreeThreads  
  如果收到   HTTP   503   错误(“服务暂时过载”),则表明线程池中的线程已全部占用,并且请求队列也已超出最大值(appRequestQueueLimit   的默认设置为   100)。对于   IIS   5.0   安装,可以简单地增加线程池的大小。而对于   IIS   6.0   安装(与   IIS   5.0   不兼容),这些设置将无效。  
  maxWorkerThreads   和   maxIoThreads   分别控制工作线程数以及处理新提交的   ASP.NET   请求的线程数。这些设置需要在您的   Machine.config   中进行配置,它们将影响您计算机上运行的所有   Web   应用程序。maxWorkerThreads   是   Machine.config   中的   processModel   元素的一部分,并且您在查看后会发现,该设置的默认值为每个处理器   20   个线程。  
  minFreeThreads   设置可以在   Machine.config   中进行配置,或者在您的应用程序的   Web.config   文件中的   httpRuntime   元素下进行配置。该设置的作用是,当空闲的线程数低于所设置的限制时,将禁止使用线程池中的线程来处理传入的   HTTP   请求。如果您需要某个进程线程池线程完成挂起的请求,这会很有用。如果所有的线程都被用来处理传入的   HTTP   请求,并且这些请求在等待另一个线程完成其处理,那么就会进入死锁状态。例如,如果您正在从   ASP.NET   应用程序进行对某个   Web   服务的异步   Web   服务调用,并且在等待回调函数完成该请求,就会出现这种情况。因为回调必须在进程线程池中的空闲线程上进行。如果查看一下您的   Machine.config,将会注意到   minFreeThreads   设置的默认值为   8,如果工作线程池的限制为   20,则该默认值还可以满足需要,但是,如果线程池的大小增加到   100,该默认值就太小了。  
  应当注意的是,如果您的   ASP.NET   应用程序对本地计算机进行   Web   服务调用,则线程池限制的问题将被激化。例如,我为此专栏创建的测试应用程序调用与   ASPX   页面同处一台计算机上的   Web   服务。因而,对于阻塞的调用,一个线程被同时用于   ASPX   页面和   ASMX   Web   服务请求。这有效地使   Web   服务器处理的同时请求数增加了一倍。在同时进行两个   Web   服务请求(使用异步   Web   服务调用)的情况下,我们最终使同时进行的请求数增加了两倍。为避免在回调本地计算机时出现此类问题,您应当考虑您的应用程序的体系结构,使其简单地直接从   ASPX   代码来执行   Web   方法中的代码。  
  Windows   XP   限制  
  我们必须要注意,如果您在一个   Windows&reg;   XP   计算机上进行某项测试,则所面临的另一个限制是   XP   Web   服务器对所允许的同时连接数的人为限制。因为   Windows   XP   不是服务器平台,其同时连接数被限制为   10。这对于开发环境中的测试通常没问题,但是如果试图进行任何复杂的测试,该限制问题就会比较严重。本地计算机的连接不受此限制影响。  
  真正的解决方案:异步请求处理    
  调整配置设置是一种改善问题的方法,而在实际设计   Web   应用程序时通过某种方式彻底解决问题则是另一回事。等待阻塞的调用完成的线程永远也不会有更好的调整余地,因此,解决的办法是完全避免阻塞问题。异步处理请求就是一个适当的解决方案。这表现在两个方面:进行异步   Web   服务调用,以及在   ASP.NET   Web   应用程序中异步处理请求。