原文连接:http://www.cnblogs.com/hgamezoom/p/3082538.htmlhtml
一个ASP.NET项目在部署到生产环境时,当用户并发量达到200左右时,IIS出现了明显的请求排队现象,发送的请求都进入等待,没法及时响应,系统基本处于不可用状态。因经验不足,花了不少时间精力解决这个问题,本文记录了我查找问题的过程和最后解决方案,供你们参考。web
软硬件环境:服务器
IBM刀片服务器,Intel至强处理器,4物理核,16个逻辑核心,内存32G并发
Windows Server2008 Enterprise R2, ASP.NET 4.0 Webform IIS7.5 集成模式布局
当发现请求明显延迟,没有被即时处理的现象,首先就要查看Windows自带的性能日志Performance Monitor。性能
因为我注意到只有对于.aspx或.ashx的请求才会延迟,而.htm或.jpg文件都是即时响应的,因此很明显问题出在ASP.NET上,因而我选择了性能监视器中的ASP.NET 4.0中的2个主要计数器:Requests Current(当前请求数), Requests Queued(被排队的请求数)进行观察。经过观察发现,当前请求数达到200左右时,被排队的请求数就从0开始上升,一直到50左右,若是请求数继续上升,则被排队数也随之上升。当被排队的请求数>0时,就意味着这个时候去访问任何.aspx页面,页面都会处于长时间等待中,没有任何响应,直到IIS处理完了其余请求,才会开始处理队列中的请求。也就是说,当排队数长期>0时,系统基本处于不可用的状态。测试
因为这个系统的页面布局比较复杂,采用了大量的Ajax+.ashx的方式,将内容分批展现在页面上,因此对服务器的请求总数会比传统aspx模式来的多一些,一个页面所有加载完毕可能须要5-10秒,但我想这不该该是形成问题的主要缘由,就算系统性能较差,IIS也应该足以承受这么小的并发量的。网站
为探究究竟是系统写的有问题,仍是IIS自己的问题,我抛开咱们的系统,写了一个简单的页面,就一个aspx文件,page_load里sleep 10秒。假设这就是一个性能比较差的网站,每一个页面都要10秒才能展示,我将其部署在IIS上测试其性能,我使用的是Microsoft Web Application Stress Tool,模拟发起80个线程,每一个链接有4个Socket,总共至关于320个并发请求。线程
测试开始后,能够从下图中看到,当前请求数马上攀升到300左右(图中红线),而后队列中的请求数也上升到300左右(图中绿线),就是说在300个并发请求下,几乎全部的请求都被排队了,系统基本不可用,经过简单的测试,这个问题已经得以重现了。设计
随着时间推移,发现绿线慢慢减小,从300降低到100多,就是系统可用性渐渐提升,有一部分用户能够正常使用,但大部分还在排队。
过了6,7分钟,队列中的请求数降低到0左右,并有一些小幅波动。这个时候大部分请求能够被正常处理了。 按照这个现象分析的话,应该是IIS发现有大量请求在队列中,就会试图增长处理线程数以知足要求,可是增加速度有些缓慢。
那是否是系统通过了6,7分钟的适应期以后,之后就一直能够在这个并发量下稳定运做了呢?事实并不是如此。我将压力测试停了几秒,当服务器的请求数降为0之后,再从新开启320个请求的测试,IIS如何表现?从下图能够看到,只要请求数有明显上升,则等待队列又开始达到最高值,而后缓慢降低,重复上面的过程。总结下来就是,当出现较大并发时,IIS的处理请求能力彻底跟不上,须要很长时间才能开出足够的线程。
而后我作了一个测试,看看IIS默认状况到底能承受多少请求而不排队?彷佛是在100个并发左右,表现尚可,未出现排队。
当200个左右就不行了。
而后我将测试程序从sleep10秒改为3秒,对于一个应用系统来讲,页面平均3秒处理时间的性能该还算比较正常了。但惋惜的是,排队现象与处理时间并没有太大关系,排队仍然很严重。
针对以上问题,查阅了相关资料,是否出现排队是和应用程序池的可用线程有关,经过2个方法能够查看系统总线程数和当前可用线程数。
ThreadPool.GetAvailableThreads( out availableWorker, out availableIO);
ThreadPool.GetMaxThreads(out maxWorker, out maxIO);
在队列请求数达到120左右时,经过此方法,获得maxWorker=1600,而availableWorker=1472
由于服务器是16核的,ASP.NET4.0默认每核可使用100个线程,因此maxWorker是1600,1600-120=1480,大体相等。
就是说当前有120个线程被用来处理请求,还有1400多个处于空闲。关键问题就是为何这些空闲线程没有被及时启用?
ASP.NET提供的线程配置参数中,有一个参数是很是重要,可是可能被你们忽略的,就是minWorkerThreads。
意指最小工做线程,根据咱们以上的测试结果,IIS托管线程启动很是慢,微软也认识到了这个问题,因此提供此参数用于设置正常状况下的最小工做线程数。好比咱们系统白天的并发在200-300之间,则能够设置最小线程为300,这样系统响应速度能够大幅提升。
据此,我对配置文件(machine.config)进行了以下修改。注意都是针对单个CPU的,系统会自动乘以逻辑CPU的数量。
<system.web>
<processModel autoConfig="false" maxWorkerThreads="200" minWorkerThreads="50" />
至关于最小工做线程设置成了50*16=800。
重启IIS后进行测试,咱们获得了如下结果:
能够看到,因为设置了合理的最小工做线程数,使得IIS无需不断建立新线程来处理请求,系统的响应能力已能够知足并发要求。
除此以外,在IIS6以后引入了一个新功能叫Web Garden,其设计目的是为了在CPU占用较低,可是并发请求数比较多的状况下,提高服务器性能。这正符合我当前的状况,因而我启用了Web Garden,将工做进程数从1调整到5,在任务管理器中能够看到w3wp进程从原来的1增长到了5,而后从新测试。
一样的320个请求下,能够看到除了一开始的几秒出现了一些排队,后面基本上表现良好,没有请求进入队列。
经过以上两种方式,均可以有效解决本文开头提出的问题。但Web Garden是工做在多进程模式下,若是应用中用到了依赖进程的Session和Cache等对象都必须另想办法,不能保存在服务器内存中,并且Web Garden的多个进程切换时会有上下文复制,其资源消耗相对单进程要大,这些是须要考虑的因素。