ASP.NET 2.0 Performance Guidelines - Threading

From Guidance Share
Jump to navigationJump to search

- J.D. Meier, Srinath Vasireddy, Ashish Babbar, John Allen, and Alex Mackman


Tune the thread pool by using the formula to reduce contention

Tune ASP.NET thread pool using maxWorkerThreads, minWorkerThreads, maxIoThreads, minFreeThreads, minLocalRequestFreeThreads and maxconnection attributes in Machine.config file for reducing contention. If requests are being queued with low processor utilization levels, this is a strong indication that ASP.NET is performing non-CPU bound work.


Why

When your application uses the common language runtime (CLR) thread pool, it is important to tune the thread pool to avoid contention issues, performance problems, and possible deadlocks.


When

Use this guideline when all of the following is true for your application:

  • Your application uses the CLR thread pool
  • You have available CPU cycles
  • Your application performs I/O bound operations such as calling a Web method or accessing the file system
  • The ASP.NET Applications/Requests In Application Queue performance counter indicates that you have queued requests

If you are unsure whether your application is using the CLR threat pool you can check as follows. Your application may be using the CLR thread pool if any of these conditions is true:

  • Your application makes Web service calls.
  • Your application uses the WebRequest or HttpWebRequest classes to make outgoing Web requests.
  • Your application explicitly queues work to the thread pool by calling the QueueUserWorkItem method.


How

You can tune ASP.NET thread pool using maxWorkerThreads, minWorkerThreads, maxIoThreads, minFreeThreads, minLocalRequestFreeThreads and maxconnection attributes in Machine.config file. Here are the default settings.

</system.net>
...
  <connectionManagement>
     <add address="*" maxconnection="2" />
  </connectionManagement>
....
</system.net>
<system.web>
...
  <httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="4" ... />
  ....
  <processModel maxWorkerThreads="20" maxIoThreads="20" ... />
  ....
</.system.web>

Here is the formula to reduce contention. Apply the recommended changes that are described below, across the settings and not in isolation.

  • Configuration setting Default value (.NET Framework 1.1) Recommended value
  • maxconnection 2 12 * #CPUs
  • maxIoThreads 20 100
  • maxWorkerThreads 20 100
  • minFreeThreads 8 88 * #CPUs
  • minLocalRequestFreeThreads 4 76 * #CPUs


  • Set maxconnection to 12 * # of CPUs. This setting controls the maximum number of outgoing HTTP connections that you can initiate from a client. In this case, ASP.NET is the client. Set maxconnection to 12 * # of CPUs.
  • Set maxIoThreads to 100. This setting controls the maximum number of I/O threads in the .NET thread pool. This number is automatically multiplied by the number of available CPUs. Set maxloThreads to 100.
  • Set maxWorkerThreads to 100. This setting controls the maximum number of worker threads in the thread pool. This number is then automatically multiplied by the number of available CPUs. * Set maxWorkerThreads to 100.
  • Set minFreeThreads to 88 * # of CPUs. This setting is used by the worker process to queue all the incoming requests if the number of available threads in the thread pool falls below the value for this setting. This setting effectively limits the number of requests that can run concurrently to maxWorkerThreads – minFreeThreads. Set minFreeThreads to 88 * # of CPUs. This limits the number of concurrent requests to 12 (assuming maxWorkerThreads is 100).
  • Set minLocalRequestFreeThreads to 76 * # of CPUs. This setting is used by the worker process to queue requests from localhost (where a Web application sends requests to a local Web service) if the number of available threads in the thread pool falls below this number. This setting is similar to minFreeThreads but it only applies to localhost requests from the local computer. Set minLocalRequestFreeThreads to 76 * # of CPUs.

Note The recommendations that are provided in this section are not rules. They are a starting point. Test to determine the appropriate settings for your scenario. If you move your application to a new computer, ensure that you recalculate and reconfigure the settings based on the number of CPUs in the new computer.


Problem Example

A high traffic ASP.NET application is deployed on a 2 proc machine. When the following performance counters are monitored, it displays low CPU utilization however requests are becoming queued up resulting in low throughput.

ASP.NET\Requests Queued Process\% Processor Time (aspnet_wp.exe or w3wp.exe) The applications configuration settings are as follows:

</system.net>
...
  <connectionManagement>
     <add address="*" maxconnection="2" />
  </connectionManagement>
....
</system.net>
<system.web>
...
  <httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="4" ... />
  ....
  <processModel maxWorkerThreads="20" maxIoThreads="20" ... />
  ....
</.system.web>


Solution Example

A high traffic ASP.NET application is deployed on a 2 proc machine. The thread pool settings are configured using the formula for reducing contention. This improves the CPU utilization and lowers request queuing, giving better throughput.

The application configuration settings are as follows:

</system.net>
...
  <connectionManagement>
     <add address="*" maxconnection="24" />
  </connectionManagement>
....
</system.net>
<system.web>
...
  <httpRuntime minFreeThreads="176" minLocalRequestFreeThreads="152" ... />
  ....
  <processModel maxWorkerThreads="100" maxIoThreads="100" ... />
  ....
</.system.web>


References


Configure minIoThreads and minWorkerThreads for Burst Load

Use the minIoThreads and minWorkerThreads settings in Machine.config file to configure a minimum number of worker threads and I/O threads for load conditions. Additionally you can use the SetMinThreads method to increase the number of idle Worker threads and the number of I/O completion threads that the ThreadPool class maintains.


Why

If your application experiences burst loads seperated by prolonged periods of inactivity, the thread pool may not have enough time to reach an optimal level of threads. The sudden requirement for a larger number of threads from the ThreadPool class may result in slow computer response time. If the minimum number of Worker threads or I/O threads is configured, the ThreadPool immediately creates new threads up to the minimum number specified during a time of high load. Thus improving the response time and performance of the application in burst loads as well. After inactivity, these threads die.


When

Tune the minimum number of threads only when there is load on the Web server for short periods of time (10 minutes or less) and your application shows decline in response time.


How

There are two methods for setting the minIoThreads and minWorkerThreads for ThreaPool class. The recommended value for both the attributes is 50, but it may not work for all applications. You will have to tune the setting which is best for your application.

Using configuration In the <processModel> configuration section in the Machine.config, set the following attributes. Note these attributes are not in the configuration file by default. You must add it. minWorkerThreads: Configures the minimum number of worker threads to be used for the process on a per-CPU basis. For example, if this value is 10 on a single-processor server, ASP.NET uses the runtime APIs to set the process limit to 10. On a two-processor server, the limit is set to 20. The default is 0.

minIoThreads: Configures the minimum number of asynchronous I/O threads to be used for the process on a per-CPU basis. For example, if this value is 10 on a single-processor server, ASP.NET uses the runtime APIs to set the process limit to 10. On a two-processor server, the limit is set to 20. The default is 0.

<system.web>
...
  <processModel minWorkerThreads=10 minIoThreads=10 .../>
...
</system.web>

Programmatically Additionally you can use following API of the ThreadPool class for setting the minimum number of worker threads and the minimum number of asynchronous I/O threads for the ThreadPool programmatically.

public static bool SetMinThreads(int workerThreads, int completionPortThreads);

If you want to know the current setting for minimum number of worker threads and the minimum number of asynchronous I/O threads for the ThreadPool, use the GetMinThreads method of ThreadPool class.

public static void GetMinThreads(out int workerThreads, out int completionPortThreads); 


Problem Example

An ASP.NET application declares lottery results every day at 10:00 AM and 4:00 PM. There is a heavy load on the Web server for short periods of time directly after the lottery results are declared. The application has been deployed with default minThreads configuration setting of 0 threads. The problem with this application is that the ThreadPool does not have enough time to reach the optimal level of threads to handle the load and hence users experience slow response.

!!! Solution Example An ASP.NET application which declares lottery results every day at 10:00 AM and 4:00 PM. There is heavy load on the Web server only for short periods after the lottery results are declared. The minimum number of Worker threads or I/O threads is configured to 10 threads.

When the application starts, the ThreadPool immediately creates 10 threads to handle heavy load. If 10 threads is not enough, more threads will be allocated at half-second intervals. Thus user experience better response improving the performance of the application.

<system.web>
...
  <processModel minWorkerThreads=10 minIoThreads=10 .../>
...
</system.web>


References


Do Not Create Threads on a Per-Request Basis

Avoid manually creating threads on each client request. But if you have work that is not CPU bound that can run in parallel, use the infrastructure provided by the .NET Framework or CLR thread pool for asynchronous processing.


Why

Creating threads is an expensive operation that requires initialization of both managed and unmanaged resources.


When

Consider using asynchronous calls if you have work that is not CPU bound that can run in parallel with the call. For example, this might include disk I/O bound or network I/O bound operations such as reading or writing files, or making calls to another Web method.


How

Use following options for asynchronous processing.

Use the infrastructure provided by the .NET Framework You can use the infrastructure provided by the .NET Framework to perform asynchronous operations by calling the Beginsynchronous and Endsynchronous methods (where synchronous represents the synchronous method name)

Use CLR thread pool If the above asynchronous calling pattern is not an option, then consider using threads from the CLR thread pool. The following code fragment shows how you queue a method to run on a separate thread from the thread pool.

WaitCallback methodTarget = new WaitCallback(myClass.UpdateCache);
bool isQueued = ThreadPool.QueueUserWorkItem(methodTarget);


Problem Example

An ASP.NET application performs long running processing on a separate thread. Unfortunately it creates a thread per request thus making the application less performant.

.....
ThreadStart methodTarget = new ThreadStart(myClass.DoLongRunningWork);
Thread myThread = new Thread(methodTarget);
myThread.Start();
.....

!!! Solution Example An ASP.NET application performs long running processing on a separate thread. This code sample uses threads from the CLR thread pool for executing the long running process asynchronously. This approach does not have the overhead associated of manually creating new threads thus improving performance.

...
WaitCallback methodTarget = new WaitCallback(myClass.DoLongRunningWork);
bool isQueued = ThreadPool.QueueUserWorkItem(methodTarget);
...


References