ASP.NET 线程详解

本文是博主翻译文章,估计会省略一些,但是我尽量能翻译好,各个知识点通俗易懂。译文如下:

ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0  

我简短的解释下asp.net被宿主在 IIS 7.5, IIS 7.0 and IIS 6.0中的时候,是如何处理线程的,而且还有configuration中默认值的修改 

 

Please take a quick look at the “Threading Explained” section in Chapter 6 of “Improving .NET Application Performance and Scalability”.【后面翻译】

请快速查看“Threading Explained” 部分,在第六章: “Improving .NET Application Performance and Scalability” 【后面翻译】

 

优先.net2.0,调整如下配置是很有必要的:

                           processModel/maxWorkerThreads

                           processModel/maxIoThreads

                           httpRuntime/minFreeThreads,

                           httpRuntime/minLocalRequestFreeThreads,

                           connectionManagement/maxconnection 

net2.0尝试简化配置它,使用一个新的配置processModel/autoConfigprocessModel/autoConfig为你在运行时调整上文的5个配置的更改。

在iis7.0和ASP.NET集成管道的介绍中,我们已经引进了另一个元素去组合,一个注册表项名叫:MaxConcurrentRequestsPerCPU,在讨论iis7.0的更改配置前,让我们先讨论在iis6.0中是如何工作的。

ASP.NET被host在iis6的时候,在iis的 i/o线程中的请求传递ASP.NET处理。ASP.NET立即提交请求给the CLR ThreadPool 和返回HSE_STATUS_PENDING给iis。 

这个释放了iis的线程,可以让iis去为其他请求服务,比如静态文件。

 

提交给CLR Threadpool 的请求也作为一个队列行动,

The CLR Threadpool 依据负载自动调整线程数量,以便如果请求是一个高的生产力,他将为每一个cpu分配仅仅1或者2个线程,如果是延迟情况,将要有潜在的更多并发执行。

 

 被CLR Threadpool 实现的这个队列是非常有用的,因为当请求在队列中,仅仅有非常小的数量内存为请求分配,它们全是原生的内存。它不用等到一个线程整理请求和开始执行线程的托管代码和分配托管内存。

 

在host   iis6的时候, The CLR Threadpool不是仅仅这个队列被ASP.NET使用。

也有队列在应用层面,在每一个AppDomain里面。

如果有大量的延迟,the CLR Threadpool将生成和注入更多的活动线程。

在一些情况下,我们既不要耗尽线程,没有足够的线程为其他任务工作留下,或者全部并发执行请求所关联的内存将要太多,因此,asp.net利用一个cap在线程并发执行请求的数量上。

它被httpRuntime/minFreeThreads and httpRuntime/minLocalRequestFreeThreads 控制

如果这个cap被超过,请求被排队在应用级别的队列中和稍后被执行,这个时候并发将掉落到限制以下。这些应用级别的队列是真的非常悲惨。如果你观察 性能计数器 “ASP.NET Applications\Requests in Application Queue”的值非零,你肯定有一个性能问题。 

这些队列被实现去避免线程耗尽和关系到web service请求的竞争,问题被首先描述在KB 821268,这个是我发布很多年前。这篇文章自从最初发布已经被我重写一些次数,我希望在转变中没有任何丢失。

对于大多数场景,在KB文章中的更改建议是没有必要的,因为v2.0引进了processModel/autoConfig

无论如何,autoconfig配置或许没有每次都会工作,它限制每个cpu并发执行请求数量到12.一个有高延迟的应用或许想要比这个更高的并发,在这种情况下你能禁止autoconfig,去自己配置更改。

如果你允许更高的并发,保持关注你的工作组。我相信默认的达到90%的应用需要处理。自从它可以被非常简单的去配置,我希望我们对那个名叫maxConcurrentRequestsPerCPU的配置的设置有自己的预判,和允许它习惯的去控制并发。当业务是仅仅比我们认为的稍微快一点的时候,我猜这仅仅是我们另外的一个经验案例了。

ASP.NET被宿主在iis7.5和7.0的继承模式的时候,线程使用是一点不同,首先,应用程序级别的层是不再有。

他们的工作表现总是很坏,不希望去解决它,因此我们去拜托他们。

然而或许最大的不同是,在iis6.0或者ISAPI模式下,ASP.NET限制执行并发请求的线程的数量,但是在11s7.5和7.0继承模式,ASP.NET限制执行请求的数量。

不同仅仅在请求是异步的时候有重大影响(请求或者有一个异步的handler,或者一个在he pipeline completes asynchronously的一个moudlule)

明显的,如果请求是同步的,这时候执行请求的并发数量是和执行请求线程的数量是相同的,但是如果请求是异步的,这时候这两个数量可以是非常不同的,因为你可以比线程数有很多的请求数。

因此准确点,在继承模式,如何做?与iis6.0相似(经典模式),请求任然处理在iis I/O线程到asp.net. ASP.NET立即提交请求到he CLR Threadpool和返回待定。

我们发现这个线程切换保留下来是有必要的,对于静态文件优化性能来说。因此虽然你将要有一次性能损失,如果你仅仅是执行asp.net请求,如果你有一个和静态文件的混合,正如我们的一个大的团队,这个线程切换将释放线程为检索静态文件使用。

最后,一旦请求被一个线程从 the CLR Threadpool中拿起,我们检查去看有多少请求是当前在执行。如果数量是太高,请求被排队在一个global (process-wide) queue 

这个global,原生的队列工作比我运行在 ISAPI 模式下(和在IIS 6.0运行相同)的the application-level queues要好太多了。

有非常小的内存关联到队列请求,和我们还没有进入到托管代码,因此没有托管内存关联他们。

还有我们很关心一个队列先进先出的方面,在同 the application-level queues我们没有做一些事情,如果有一个以上的应用,没有简单的途径去全局管理独立的队列。我们无论无何有一段艰难日期去设法为IIS7.0的更改想出一个好的配置方案。 

我讨论如何去为ASP.NET/IIS7.0集成模式配置线程使用的时候,请记住我们有大堆先存在的代码和配置,然后你不能仅仅创建某些新的途径,而不想引进向后兼容问题。 

在这个新的模型,the CLR Threadpool是仍然被 the processModel configuration settings (autoConfig, maxWorkerThreads, maxIoThreads, minWorkerThreads, and minIoThreads)这些所控制。

然后autoConfig是仍然是开启,但是自从the application-level queues不存在,它的修改对httpRuntime/minFreeThreads and httpRuntime/minLocalRequestFreeThreads 不起任何作用。

或许我们应当尝试去使用他们去配置进程范围的global 队列限制,但是他们有应用程序范围(httpRuntime configuration 是应用程序的详述),不是进程范围,没有说起是因为非常难明白。然后因为the configuration system的一些问题我不将立刻进入,我们决定使用一个注册表项去控制并发。

因此,作为iis7继承模式,一个名叫MaxConcurrentRequestsPerCPU 的DWORD在 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0 决定每个cpu控制并发请求的数量。

默认情况下,它不存在和每个cpu的请求数量被限制在12.

如果你是好奇去看到ASP.NET请求执行在没有线程切换下有多么的快,你能设置值为0.这将引起请求执行在 IIS I/O 线程,没有切换到CLR Threadpool thread

我首先不推荐,因为动态请求花费很长时间去执行涉及到的静态请求,然后我相信全部系统的性能在同 the thread switch一起是最好的。无论如何,这是重要的。

如果你的应用主要或者完全是异步请求组成,the defaultMaxConcurrentReqeustsPerCPU为12的限制将是对你来说太约束了,尤其如果请求是长时间运行。

在这个案例,我推荐配置MaxConcurrentRequestsPerCPU为一个非常高的数量,实际上,在 v4.0,我们已经更改默认MaxConcurrentRequestsPerCPU的值为5000。

关于5000没有特别的,不同的是他是一个非常大的数字,顾将允许大量异步请求去并发执行。

一件需要小心的事是。并发增高的时候,你的应用仅仅将使用更多的内存,因为有更多请求执行在托管代码。

The CLR ThreadPool仍然将做一个非常伟大的工作,维护线程池中的线程数量,因此应当不用关心关于这个同步请求的不利影响。

我知道有人使用 ASP.NET 2.0 和开发 Comet or Comet-like 应用在n WS08 x64 servers,然后他们设置MaxConcurrentRequestsPerCPU为5000和增加HTTP.sys内核队列限制到 10,000(它默认是1000).

HTTP.sys内核队列限制是被iis控制,你能改变它在 IIS Manager 和为你的 应用程序池 打开  高级设置选项更改 Queue Length 的值。

 

 

 

最后生命,请记住 processModel/requestQueueLimit配置限制最大请求数量在ASP.NET系统,为IIS 6.0, IIS 7.0, and IIS 7.5。这个数字被暴露在 “ASP.NET/Requests Current” 性能计数器,然后当他被超过时,我们拒绝请求,返回一个503 HTTP状态:意思是  服务繁忙。

 

-Thomas

 

UPDATE (Aug-18-2008): 

 .NET Framework v3.5 SP1 这周较早一点发布了,它包括一个针对 v2.0二进制的更新,支持配置iis应用程序池通过aspnet.config文件。

aspnet.config文件不是非常熟悉,他是CLR Hosting配置文件,然后 当 the CLR被加载的时候,ASP.NET/IIS通过它到the CLR

The host configuration file应用配置在进程级别,正如web.config对于应用级别。

有一个新的 system.web/applicationPool 配直节仅仅应用到集成模式(经典或者isapi模式排除这些配置)。新的配直节以及默认值如下

    <system.web>
        <applicationPool maxConcurrentRequestsPerCPU=”12″ maxConcurrentThreadsPerCPU=”0″ requestQueueLimit=”5000″/>
    </system.web>

有一个相似IIS 7.5的更改 (Windows Server 2008 R2 only) ,允许不同的aspnet.config文件去为每一个应用程序池详细说明(这个更改还没有移植到iis7.0)

有了这个,你能配置每一个不同的应用程序池。

The maxConcurrentRequestsPerCPU配置是如同上面的注册表值一样的,除了在aspnet中的配置。配置将覆盖注册表键值的配置。

The maxConcurrentThreadsPerCPU配置是新的,然后允许去作为并发的关于线程数量的入口,相似的途径他在经典模式下已经做过。

默认,maxConcurrentThreadsPerCPU被禁止(有一个0值)

正常情况下,你将使用请求阀门,但是你现在有一个禁止(set maxConccurrentRequestsPerCPU=0)和使maxConccurentThreadsPerCPU 运行。

你能总是使请求和线程阀门都运行在相同的时间,然后ASP.net将是他们安全相遇。

 

UPDATE (Sep-12-2011):  仅有关联到 .NET Framework v4.0是maxConcurrentRequestsPerCPU默认值增加到5000.

5000也可以用在versions 2.0 and 3.5,他们默认是12.

同样,据我对设计的线程了解,iis7.5对iis7.0是相同的。

仅有的不同在iis7.5和7.0之间,就是关系去支持配置不同的asp.net文件为每个程序池。

You do this by setting the CLRConfigFileattribute for the application pool.  You can then use the system.web applicationPool configuration mentioned above to set different values for maxConcurrentRequestsPerCPU, maxConcurrentThreadsPerCPU, and requestQueueLimit, if desired. 

 大体上,运行默认配置最好,无论如何,应用程序都有潜在因素,说是100毫秒的延迟,当和一个web service通讯的时候,一些少的配置更改,是最好。让我告诉你什么你应当如何进行配置更改在iis7/7.5的集成模式下,以便应对 一个有大量并发请求的延迟滞后。一个大的并发请求数,我的意思是12到5000之间没cpu。

 

 

1   For v2.0 and v3.5 set a DWORD registry value @ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0\MaxConcurrentRequestsPerCPU = 5000.  Restart IIS

2  For v3.5, you can alternatively set <system.web><applicationPool maxConcurrentRequestsPerCPU=”5000″/></system.web> in theaspnet.config file.  If the value is set in both places, the aspnet.config setting overrides the registry setting.

3   For v4.0, the default maxConcurrentRequestsPerCPU is 5000, so you don’t need to do anything.
4    Increase the HTTP.sys queue limit, which has a default of 1000.  If the operating system is x64 and you have 2 GB of RAM or more, setting it to 5000 should be fine.  If it is too low, you may see HTTP.sys reject requests with a 503 status.  Open IIS Manager and the Advanced Settings for your Application Pool, then change the value of “Queue Length”.
5  If your ASP.NET application is using web services (WFC or ASMX) or System.Net to communicate with a backend over HTTP you may need to increase connectionManagement/maxconnection.  For ASP.NET applications, this is limited to 12 * #CPUs by the autoConfigfeature.  This means that on a quad-proc, you can have at most 12 * 4 = 48 concurrent connections to an IP end point.  Because this is tied to autoConfig, the easiest way to increase maxconnection in an ASP.NET application is to set System.Net.ServicePointManager.DefaultConnectionLimit programatically, from Application_Start, for example.  Set the value to the number of concurrent System.Net connections you expect your application to use.  I’ve set this to Int32.MaxValue and not had any side effects, so you might try that–this is actually the default used in the native HTTP stack, WinHTTP.  If you’re not able to set System.Net.ServicePointManager.DefaultConnectionLimit programmatically, you’ll need to disable autoConfig , but that means you also need to set maxWorkerThreads and maxIoThreads.  You won’t need to set minFreeThreads or minLocalRequestFreeThreads if you’re not using classic/ISAPI mode.
6  如果你看到一个大的并发请求在启动时,或者有一个繁忙的加载,并发增加突然,你将需要去让你的应用异步,因为CLR ThreadPool 没有很好的反应这些加载。 .线程池注入新的线程在大约每秒两个的速度。如果并发是繁忙的和请求线程阻塞,每秒两个的速度将让你的应用反应非常匮乏,解决停止在线程阻塞是用异步去和后端通讯,如果你不能作为异步程序,你将需要去增加minWorkerThreads。我不喜欢去增加minWorkerThreads线程,它在高流量同步请求有副作用,因为线程是相当的高         

 

 

 

 

 

 

 

 

 

  1. 引用:https://blogs.msdn.microsoft.com/tmarq/2007/07/20/asp-net-thread-usage-on-iis-7-5-iis-7-0-and-iis-6-0/

 

posted @ 2017-05-20 23:06  无为有道  阅读(854)  评论(0编辑  收藏  举报