I ' d like to briefly explain how ASP uses threads when hosted on IIS 7.5, IIS 7.0 and IIS 6.0, as well as the Configura tion changes that's can make to alter the defaults. Click a quick look at the "threading explained" section In chapter 6 of "improving. NET application Perfor Mance and Scalability ". Prior to v2.0 of the. NET Framework, it is necessary to tweak the processmodel/maxworkerthreads, Processmodel/maxiothread S, Httpruntime/minfreethreads, Httpruntime/minlocalrequestfreethreads, and Connectionmanagement/maxconnection Configuration. The v2.0. NET Framework attempted to simplify this by adding a newprocessmodel/autoconfig configuration, which made T He changes for your at runtime. With the introduction of IIS 7.0 and the ASP. Integrated pipeline, we ve introduced another element to the mix, a Regis Try key named maxconcurrentrequestspercpu. Lets start with a discussion of what things worked on IIS 6.0 before discussing the changes made in IIS 7.0.
When ASP. Hosted on IIS 6.0, the request was handed over to ASP. NET on an IIS I/O thread. ASP. Immediately posts the request to the CLR ThreadPool and returns hse_status_pending to IIS. This frees up IIS threads, enabling IIS to serve other requests, such as static files. Posting the request to the CLR Threadpool also acts as a queue. The CLR Threadpool automatically adjusts the number of threads according to the workload, so if the requests is high Throughput there would only be 1 or 2 threads per CPU, and if the requests is high latency there would be potentially far More concurrently executing requests than 1 or 2 per CPU. The queuing provided by the CLR Threadpool was very useful, because while the requests was in the queue there was only a ver Y small amount of memory allocated for the request, and it's all native memory. It's not until a thread picks up the request and begins to execute that we enter managed code and allocate managed memory.
The CLR Threadpool is isn't the only queue used by ASP. Hosted in IIS 6.0. There is also queues at the application level and within each AppDomain. If There is a lot of latency, the CLR Threadpool would grow and inject more active threads. At some point we would either run out of threads, not having enough threads left over for performing other tasks, or the MEM Ory associated with all the concurrently executing requests would is too much, so ASP. Imposes a cap on the number of T Hreads concurrently executing requests. This was controlled by the Httpruntime/minfreethreads and httpruntime/minlocalrequestfreethreads settings. If the cap is exceeded, the request was queued in the Application-level queue, and executed later when the concurrency fall s back down below the limit. The performance of these application-level queues is really quite miserable. If you observe the "ASP. Applications\requests in Application Queue" performance counter are Non-zero, you definite Ly has a performance problem. These queues were implemented to prevent thread exhaustion and contention related to Web service requests. The problem was first described in kb 821268, which I had published many years ago. The KB article has been re-written a few times since it is originally published, and I hope nothing had been lost during The translations.
For more usage scenarios, the changes recommended in the KB article is not necessary because V2.0 Introducedprocessmod El/autoconfig. However, the AutoConfig setting may isn't work for everyone–it limits the number of concurrently executing requests per CPU to 12. An application-with-latency may want-allow higher concurrency than this, in which case can disable AutoConfig And make the changes yourself. If you don't allow higher concurrency, keep a eye on your working set. I believe the default works for about 90% of the applications out there. I do wish we had the foresight to name this setting MAXCONCURRENTREQUESTSPERCPU, and allow it to is used to control concur Rency, since that would is much easier to configure. I Guess this is just another example's when business was just a little bit faster than the speed of thought.
When ASP. Hosted on IIS 7.5 and 7.0 in Integrated mode, the use of threads is a bit different. First of all, the Application-level queues is no more. Their performance is always really bad, there is no hope in fixing it, and so we got rid of them. But perhaps the biggest difference are that in IIS 6.0, or ISAPI mode, ASP. The number restricts Ncurrently executing requests, but in IIS 7.5 and 7.0 Integrated mode, ASP. Restricts the number of concurrently execut Ing requests. The difference only matters when the requests is asynchronous (the request either have an asynchronous handler or a module In the pipeline completes asynchronously). Obviously if the reqeusts is synchronous, then the number of concurrently executing requests is the same as the Number of threads concurrently executing requests, but if the requests is asynchronous then these a numbers Can is quite different as you could has far more reqeusts than Threads. So how does things work, exactly, in Integrated mode? Similar to IIS 6.0 (Classic mode, a.k.a. ISAPI mode), the request was still handed over to ASP. and ASP. Immediately posts the request to the CLR Threadpool and returns pending. We found this thread switch is still necessary to maintain optimal performance for static file requests. So although you'll take a performance hits if you ' re only executing ASP. Requests, if you have a mix of dynamic and St atic files, as we see with many large corporate workloads, this thread switch would actually free up threads for retrieving The static files. Finally, once the request is picked-a thread from the CLR Threadpool, we check to see how many requests is currentl Y executing. If The count is too high, the request was queued in a global (process-wide) queue. This global, native queue performs much better than the Application-level queues used when we ' re running in ISAPI mode (SA Me as on IIS 6.0). THere are very little memory associated with a queued request, and we had not entered managed code yet so there are no manag Ed memory associated with it. And we respect the FIFO aspect of a queue, something we didn ' t do with the Application-level queues–if there were more than One application, there is no simple-to-globally manage the individual queues. We did however has a difficult time trying to come up with a good configuration stories for the IIS 7.0 changes.
When I discuss how to configure the thread usage for Asp.net/iis 7.0 Integrated mode, please remember the We have a lot of PR E-existing code and configuration, and you can ' t just create something new the the-the-the-the-the-the-the-would like to without introducing B Ackward compatibility issues. In this new mode, the CLR Threadpool are still controlled by the ProcessModel configuration settings (AutoConfig, Maxworker Threads, Maxiothreads, minWorkerThreads, and Miniothreads). And AutoConfig are still enabled, but their modifications to httpruntime/minfreethreads and Httpruntime/minlocalrequestfreet Hreads does nothing, since the Application-level queues does not exist. Perhaps we should has tried to use them to configure the global (Process-wide) queue limits, but they has application SC Ope (httpRuntime configuration is application specific), not process scope, ' not ' mention being too difficult to Understa nd. And because of some issues with using the configuration system that I won ' t go to right now, we decided To Use a registry key to control concurrency. So for IIS 7.0 Integrated mode, a DWORD named maxconcurrentrequestspercpu within hkey_local_machine\software\ microsoft\asp.net\2.0.50727.0 determines the number of concurrent requests per CPUs. By default, it does not exist and the number of requests per CPU are limited to 12. If you ' re curious to see how much faster ASP. Requests execute without the thread switch, you can set the value to 0. This would cause the request to execute on the IIS I/O thread, without switching to a CLR Threadpool thread. I don ' t recommend this primarily because dynamic requests take a long time to execute relative to static requests, and I B Elieve The overall performance of the system is better with the thread switch. However, and this is important, if your application consists of primarily or entirely asynchronous requests, the DEFAULTMA Xconcurrentreqeustspercpu limit of too restrictive for you, especially if the requests isVery long running. In the case, I do recommend setting maxconcurrentrequestspercpu to a very high number. in fact, in V 4.0, we have changed the default for MAXCONCURRENTREQUESTSPERCPU to 5000. there's nothing special about than it is a very large number, and would therefore allow plenty of the async requests to execute concurrently. one thing To watch out for was that when concurrency increases, your application would use more memory simply because there was More requests executing in managed code. the CLR ThreadPool would still do a great job maintaining the number of thre Ads in the ThreadPool, so there should is no concern about this adversly impacting synchronous requests. I know ther E is people using ASP. 2.0 and Developing comet or comet-like applications on WS08 x64 servers, and they set Maxconcurrentrequestspercpu to increase the HTTP. sys kernel queue limit to-(it has a default of $). &NB Sp THe HTTP kernel queue limit is controlled by iis. You can change it by opening IIS Manager and opening the A dvanced Settings for your application pool and changing the value of "Queue Length".
As a final remark, please note that the Processmodel/requestqueuelimit configuration limits the maximum number of requests In the ASP. System for IIS 6.0, IIS 7.0, and IIS 7.5. This was exposed by the "asp.net/requests" performance counter, and when it exceeds the limit (default is 50 XX) We reject requests with a 503 status (Server Too Busy).
-thomas
Update (aug-18-2008):. NET Framework v3.5 SP1 released earlier this week and it includes a UPDATE to the v2.0 binaries That supports configuring IIS application pools via the Aspnet.config file. the Aspnet.config file was not very well known. It is the clr hosting configuration file, and Asp.net/iis pass it to the CLR when the CLR is Loade D. the Host Configuration file (Aspnet.config) applies configuration at the Process-level, as opposed to T He application-level like web.config. there are a new system.web/applicationpool configuration section Which applies to Integrated mode only (CLASSIC/ISAPI mode ignores these settings). the new config sections with Defaul T values is:
<system.web>
<applicationpool maxconcurrentrequestspercpu= "12″maxconcurrentthreadspercpu=" 0″requestqueuelimit= "5000″/>
</system.web>
There is a corresponding IIS 7.5 change (Windows Server 2008 r2 only) which allows different aspnet.config Files to is specified for each application the pool (this is the been ported to IIS 7.0). With this, you can configure each application pool differently. The MAXCONCURRENTREQUESTSPERCPU setting is the same As the registry key described above, except that the setting in Aspnet.config would override the registry key value. The MAXCONCURRENTTHREADSPERCPU setting is new, and allows concurrency to being gated by the number of threads, similar to the The on-the-Classic/isapi mode. by default maxconcurrentthreadspercpu is disabled (have a value of 0), in fav or of gating concurrency by the number of requests, primarily BECAUSE&NBSP;MAXCONCURRENTREQUESTSPERCPU performs better (GA Ting the number of threads is more complicated/costly to implement) . normally you'll use request gating Have the option of disabling it (set Maxconccurrentrequestspercpu=0) and enabling MAXCONCCURENTTHREADSPERCPU instead. You can also enable both request and thread Gatin G at the same time, and ASP. Ensure both requirements is met. the requestQueueLimit setting is the same as Processmodel/requestqueuelimit, except that the setting in Aspnet.config would override the Machine.config setting. A ll of this could be a little confusing, but for nearly everyone, my recommendation are that for ASP. 2.0 You should use th E same settings as the defaults in ASP. v4.0; That is, set maxconcurrentrequestspercpu = "maxconcurrentthreadspercpu=" and "0″".
UPDATE (sep-12-2011): the. NET Framework v4.0 (as compared to 3.5 or 2.0) of the only relevant. Maxconcurrentrequestspercpu was increased to 5000. Also the value of should use in versions 2.0 and 3.5, which has a default of 12. Also, IIS 7.5 is identical-to-IIS 7.0 as far as threading. The only difference between IIS 7.5 and 7.0 are relevant to this blog post are the support to configure different Aspne T.config files for each application pool. Setting the Clrconfigfileattribute for the application pool. You can then use the system.web ApplicationPool configuration mentioned above to set different values for Maxconcurrentreq UESTSPERCPU, Maxconcurrentthreadspercpu, and requestQueueLimit, if desired.
In general, the running with the default configuration works best. However, applications that has measurable latency, say latency of milliseconds when communicating with a backend web Service, would perform better with a few configuration changes. Let me tell you about configuration changes should make on IIS 7.0 and IIS 7.5 in Integrated mode in order to handle a Large number of concurrent requests to a application that have backend latency. By large number of concurrent reqests, I mean between and the per CPU.
- 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
- 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.
- For v4.0, the default maxconcurrentrequestspercpu are the need to do anything.
- Increase the HTTP. sys queue limit, which has a default of 1000. If the operating system is x64 and you had 2 GB of RAM or more, setting it to should was 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".
- If your ASP. Application is using the Web services (WFC or ASMX) or System.Net to communicate with a backend over HTTP Need to increase connectionmanagement/maxconnection. for ASP. Applications, this was limited to 12 * #CPUs by the autoconfigfeature. This means, the on a quad-proc, can has at most 4 = Concurrent Co Nnections to a ip end point. Because this was tied to AutoConfig, the easiest of the "to" increase maxconnection in An ASP. Application is-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 app Lication to use. I ' ve set this to Int32.MaxValue and not had any side effects, so you might try That–this are actuall Y the default used in the native HTTP stack, winhttp. If your ' re not able to set System.Net.ServicePointManager.Defau Ltconnectionlimit programmatically, YOu ' ll need to disable autoconfig , but so means you also need to set maxWorkerThreads AND&NBSP;MAXIOTHREADS.&N Bsp You won ' t need to set minfreethreads or minLocalRequestFreeThreads if you ' re not using CLASSIC/ISAPI mode.
- If your application sees a large number of concurrent requests at start-up or have a bursty load, where concurrency Increas Es suddenly, you'll need to make the application asynchronous because the CLR ThreadPool does isn't respond well to these loads. the CLR ThreadPool injects new threads at a rate of about 2 per second. This is true for all versions O F The CLR (v1.0 thru v4.0) at the time of this writing. If concurrency is bursty and the request THREAD&NBSP;BL Ocks (e.g. on a backend with latency), the injection rate of 2 threads per second would make your application respond very Poorly to the load. the fix was to stop blocking on threads by using asynchronous I/O to communicate with the B Ackend with latency. If You cannot make the application asynchronous, you'll need to Increase minworkerthread s. I don t like to increase minworkerthreads. It had a side effect on high-throughput synchronous requests tha T don ' t block on threads, because the thread count is artificially high.
- Reference: https://blogs.msdn.microsoft.com/tmarq/2007/07/20/asp-net-thread-usage-on-iis-7-5-iis-7-0-and-iis-6-0/
ASP. NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0