Return to
HomePage
How To: Tune ASP.NET
Source: http://msdn.microsoft.com/library/en-us/dnpag/html/scalenetchapt17.asp
J.D. Meier, Srinath Vasireddy, Ashish Babbar, Rico Mariani, and Alex Mackman
When you approach tuning ASP.NET. consider the following:
* The client's interaction with ASP.NET. Considerations include queue sizes, timeouts (execution timeout, proxy timeouts, deadlock intervals, and session timeouts), uploading and downloading large files, and request and response sizes.
* The worker process itself. Considerations include the amount of memory allocated, view state and session state sizes, cache sizes, CPU utilization, thread affinity. If you have unavoidable thread affinity, you need to consider Web gardens.
* Remote or local Web service calls from ASP.NET. Considerations include the number of connections, and thread pool utilization.
Your approach to tuning ASP.NET should be to optimize these discrete areas from the design and code perspective first, and then to tune the individual areas.
Configuration Overview
Most ASP.NET tuning is performed by modifying configuration parameters in the system - wide Machine.config file and the application-specific Web.config file. Figure 17.10 shows an architectural view of ASP.NET and its relationship to several key configuration elements located in Machine.config.
{Insert figure: CH17 - ASPNET Tuning.gif}
Figure 17.10
Mapping of the key configuration elements with the request processing cycle
You have a number of options for tuning ASP.NET applications, most of which involve tuning the settings in Machine.config. This configuration file has many sections, but the following sections are most critical to performance.
<processModel>
The attributes on the <processModel> element apply to the ASP.NET worker process (aspnet_wp.exe) and to all applications being hosted in the worker process on an IIS 5 Web server. Many of the settings are tuned by default and do not require further changes. The default settings are as follows.
<processModel enable="true" timeout="Infinite" idleTimeout="Infinite"
shutdownTimeout="0:00:05" requestLimit="Infinite"
requestQueueLimit="5000" restartQueueLimit="10" memoryLimit="60"
webGarden="false" cpuMask="0xffffffff" userName="machine"
password="AutoGenerate" logLevel="Errors"
clientConnectedCheck="0:00:05" comAuthenticationLevel="Connect"
comImpersonationLevel="Impersonate"
responseDeadlockInterval="00:03:00" maxWorkerThreads="20"
maxIoThreads="20"/>
For a detailed description of each attribute, see "<processModel> Element" in the.NET Framework documentation at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/gngrfProcessmodelSection.asp.<httpRuntime>
The <httpRuntime> element configures the ASP.NET runtime settings. You can specify these at the machine, site, application, and subdirectory levels. The default settings from Machine.config are as follows.
<httpRuntime executionTimeout="90" maxRequestLength="4096"
useFullyQualifiedRedirectUrl="false" minFreeThreads="8"
minLocalRequestFreeThreads="4" appRequestQueueLimit="100"
enableVersionHeader="true"/>
For a detailed description of each attribute, see "<httpRuntime> Element" in the .NET Framework documentation at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/gngrfHttpRuntimeSection.asp.Thread Pool Attributes
Figure 17.11 shows thread pool configuration options for ASP.NET in context.
{Insert figure: CH17 - ASPNET Config Tuning.gif}
Figure 17.11
ASP.NET thread pool configuration options
The following list describes key attributes (in <processModel> and <httpRuntime>) in the machine.config file related to ASP.NET
ThreadPool.The list also discusses the scenarios where each attribute applies:
* maxconnection. If your application makes calls to a remote Web service and the requests are waiting for the call to complete, you can increase the CPU utilization and your application performance by changing the maxconnection attribute on the
<ConnectionManagement> element in Machine.config. The default values are as follows.
<connectionManagement>
<add address="*" maxconnection="2"/>
</connectionManagement>
Increasing maxconnection enables more calls to be executed concurrently to a remote Web service. This attribute does not affect local Web service calls. An increase in the number of concurrent calls causes an increase in the utilization of threads that are used to make the remote calls.
Increasing maxconnection also can lead to an increase in CPU utilization. This increase in CPU utilization is caused by the fact that more incoming requests can be processed by ASP.NET instead of having the incoming requests wait for their turn to call the Web service. You need to balance the maxconnection with the other attributes discussed in this list and the actual CPU utilization.
*
maxWorkerThreads and
maxIoThreads. These attributes define the maximum number of worker and I/O threads that the ASP.NET worker process is allowed to create. These values do not reflect the actual number of threads that are created by the worker process. The maximum value for these attributes is 100 per processor.
As described earlier, if you increase maxconnection, you cause increased concurrent processing, which requires a greater number of worker and I/O threads. Consider the following guidelines when tuning these attributes:
* Change these attributes only if your processor utilization is below the threshold limits defined by your application's performance objectives.
* Avoid increasing these attributes if the requests are not waiting on an I/O call but are actually performing CPU-intensive work. Increasing these attributes in this circumstance can negatively affect performance because the already stressed processor now has to handle increased thread context switching.
* If your application makes a short-running I/O call (for example, to a remote Web service), you might not need to increase these values because the calling threads are not blocked for an excessive period.
* If your application makes a long-running I/O call and your system has idle CPU, you can safely consider increasing these attributes along with the other related attributes discussed in this section. If your system does not have idle CPU, then you probably should not increase these attributes.
If you have a Web service on the same server as your Web application, consider the following to decide when to increase the default values:
* Increase these attributes only if your processor utilization is below the threshold limits defined by your application's performance objectives.
* Avoid increasing these attributes if requests are not waiting on an I/O call but are performing CPU-intensive tasks. Increasing these attributes in this situation can negatively affect performance because the already stressed processor now has to handle increased thread switching.
* maxconnection and
minFreeThreads. These attributes do not have any effect in scenarios where you make only local Web services calls.
*
minFreeThreads. This attribute defines the number of threads that can be used for work other than processing incoming requests to the worker process. This attribute prevents the ASP.NET process from using a thread from the thread pool to handle a new HTTP request if this would mean that the free thread count drops below this limit. The attribute is specified on the <httpRuntime> element and has a default value of 8.
You can use this attribute to help prevent deadlocks by ensuring that a thread is available to handle callbacks from pending asynchronous requests. A deadlock can occur if all of the threads in the thread pool are currently in use handling incoming HTTP requests, and one or more of those requests are waiting for asynchronous callbacks. In this situation, there are no available threads to service the callback. You can set
minFreeThreads to ensure that some free threads are available to process the callbacks.
Increasing
minFreeThreads means that you reserve more threads to make remote calls. In all cases, you should ensure that
maxWorkerThreads –
minFreeThreads >=12. Twelve is the optimum number of threads that should be made available to the ASP.NET worker process to service requests. This value means that ASP.NET cannot execute more than twelve requests concurrently. This limit is based on a series of performance tests, which demonstrate that normally the worker process uses four of these threads. If the processor is fully utilized (greater than 95 percent utilization) and your application makes long-running calls, the worker process is likely to use all twelve threads.
You might want to increase the attribute from the default values in the following scenarios:
* You have increased
maxWorkerThreads and
maxIoThreads. * You have increased maxconnection to service a greater number of back-end calls, and hence require more threads to be made available for this purpose.
* You might need to consider changing this attribute whenever you make long running calls which block your execution. This is most beneficial when the work is not computationally expensive for the server where you make the changes.
*
minLocalRequestFreeThreads. For a Web application using the Web service located on the same computer, you should consider decreasing the value of
minLocalRequestFreeThreads when you need to give priority to processing local calls. This attribute defines the minimum number of free threads that ASP.NET keeps available so that requests from localhost are not queued. Before processing a local request, the runtime checks to see if at least this minimum number of worker threads are available. If fewer threads are available, the request is queued.
The default setting is four, so if only three worker threads are available the local request is queued. When this value is decreased, ASP.NET starts to use threads more aggressively, resulting in less local queuing.
Note: Requests from remote clients start to queue when the free threads in the thread pool fall below the value of
minFreeThreads. If you decrease the value of
minLocalRequestFreeThreads value without changing the
minFreeThreads attribute, you are effectively telling the worker process to give priority to completing calls from the local server.
Metrics
The performance counters shown in Table 17.6 help you identify ASP.NET bottlenecks.
Table 17.6: Performance Counters Used to Identify ASP.NET Bottlenecks
Area Counter
Worker Process ASP.NET\Worker Process Restarts
Throughput ASP.NET Applications\Requests/Sec
Web Service\ISAPI Extension Requests/sec
Requests: ASP.NET\ Requests Current
ASP.NET Applications\Requests Executing
ASP.NET Applications\ Requests Timed Out
Response time / latency ASP.NET\ Request Execution Time
Cache ASP.NET Applications\ Cache Total Entries
ASP.NET Applications\ Cache Total Hit Ratio
ASP.NET Applications\Cache Total Turnover Rate
ASP.NET Applications\Cache API Hit Ratio
ASP.NET Applications\ Cache API Turnover Rate
ASP.NET Applications\ Output Cache Entries
ASP.NET Applications\ Output Cache Hit Ratio
ASP.NET Applications\ Output Cache Turnover Rate
For more information about how to measure these counters, their thresholds, and their significance, see "ASP.NET" in Chapter 15, "Measuring .NET Application Performance."
Bottlenecks
The following list describes several common bottlenecks that occur in ASP.NET applications and explains how you identify them using the system counters listed in Table 17.6. For more information about what to measure and how to measure it, see "ASP.NET" in Chapter 15, "Measuring .NET Application Performance."
* Thread pool starvation. Thread pool bottlenecks can occur when ASP.NET runs out of worker and I/O threads to process incoming requests or perform I/O work.
To identify this symptom, observe the following performance counters:
* ASP.NET\Requests Queued
* Process\% Processor Time (aspnet_wp.exe or w3wp.exe)
If requests are being queued with low processor utilization levels, this is a strong indication that ASP.NET is performing non-CPU bound work. If your application makes calls to remote or local Web services, you can tune the thread pool to resolve the issue. For detailed information about how to tune the thread pool, see "Threading Explained" in Chapter 6, "Improving ASP.NET Performance."
As an alternative, you can use custom performance counters to monitor the thread pool to investigate more about the available I/O and worker threads. For more information, see "How To: Monitor the ASP.NET Thread Pool Using Custom Counters" in the "How To" section of this guide.
* Thread contention. Thread contention occurs when multiple threads try to gain access to a shared resource, as explained in "Bottlenecks" in the "CLR Tuning" section earlier in this chapter.
* Memory bottlenecks. Memory bottlenecks can take many forms. They can result from memory leaks, fragmentation issues, inefficient resource cleanup, or simply allocating too much or too little memory for the worker process.
To identify this symptom, observe the following performance counters in addition to the system level memory-related counters discussed in the "Memory" section of this chapter.
* Process\Private Bytes (aspnet_wp.exe or w3wp.exe)
* Process\Virtual Bytes (aspnet_wp.exe or w3wp.exe)
* .NET CLR Memory\# Bytes in all Heaps (aspnet_wp.exe or w3wp.exe)
If any of these counters increases consistently and does not level off, your application has a memory leak. If # Bytes in all Heaps increases consistently along with Private Bytes, your application has a managed memory leak. If only the Private Bytes counter increases, your application has a native memory leak.
If there is a growing discrepancy between Private Bytes and Virtual Bytes, disk fragmentation may be the cause. If your application is throwing
OutOfMemoryException, this is also a strong indication that memory is a bottleneck.
You can configure the amount of memory allocated to the ASP.NET worker process by setting the memoryLimit attribute on the <processModel> element in Machine.config.
Tuning the memoryLimit attribute on the <processModel> element in Machine.config can resolve memory bottlenecks in some cases. However, if doing so does not alleviate the bottleneck, you need to further troubleshoot the problem.
* Worker Process Restarts. Restarting the ASP .NET worker process takes time and consumes resources. Set the restart threshold to an appropriate value to prevent unnecessary restarts. The following factors can contribute to recycling:
* Changes to a configuration file. (Note that these changes are not logged to the Application Log.)
* Deadlocks.
* Exceeding memory limits (<processModel memoryLimit= />).
* Request and timeout limits specified in Machine.config.
Tuning Options
Consider the following tuning options:
* Tune the thread pool using the formula for reducing contention.
* Configure the memory limit.
* Configure timeouts aggressively.
* Evaluate configuring
RequestQueue limit.
* Disable tracing and debugging.
* Disable session state if you do not use it.
* Disable View State if you do not need it.
* If you upload large files, consider
maxRequestLength. * Consider Web gardens for scenarios that benefit from processor affinity.
Tune the Thread Pool Using the Formula for Reducing Contention
The formula for reducing contention can give you a good empirical start for tuning the ASP.NET thread pool. Consider using the Microsoft product group recommended settings shown in Table 17.7 if you have available CPU, your application performs I/O bound operations (such as calling a Web method, accessing the file system, and so forth), and you have queued requests (as indicated by ASP.NET Applications\Requests In Application Queue). For more information about these individual settings, see "Tune the Thread Pool by Using the Formula to Reduce Contention" in Chapter 6, "Improving ASP.NET Performance."
Table 17.7: Recommended Threading Settings for Reducing Contention
Configuration setting Default (.NET 1.1) Recommended value
maxconnection 2 12 * #CPUs
maxIoThreads 20 100
maxWorkerThreads 20 100
minFreeThreads 8 88 * #CPUs
minLocalRequestFreeThreads 4 76 * #CPUs
To reduce contention, you need to configure the following items in Machine.config. The changes described in the list should be applied across the settings and not in isolation.
* Set maxconnection to 12 * # of
CPUs. This setting controls the maximum number of outgoing HTTP connections allowed by the client (in this case, ASP.NET). The recommendation is to set maxconnection to 12 * # of
CPUs. * Set
maxIoThreads to 100. This setting controls the maximum number of I/O threads in the CLR thread pool. This number is automatically multiplied by the number of
CPUs by the worker processor. The recommendation is to set
maxIoThreads to 100.
* Set
maxWorkerThreads to 100. This setting controls the maximum number of worker threads in the CLR thread pool. This number is automatically multiplied by the number of
CPUs by the worker processor. The recommendation is to set
maxWorkerThreads to 100.
* Set
minFreeThreads to 88 * # of
CPUs. This setting is used by the worker process to queue all of 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 concurrently executing requests to
maxWorkerThreads –
minFreeThreads. The recommendation is to set
minFreeThreads to 88 * # of
CPUs. This setting would limit the number of concurrent requests to 12 (assuming that
maxWorkerThreads is set to 100).
* Set
minLocalRequestFreeThreads to 76 * # of
CPUs. This setting is used by the worker process to queue requests from localhost (for example, your Web application sending requests to Web services on the same computer) 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 requests originating on the local server. The recommendation is to set
minLocalRequestFreeThreads to 76 * # of
CPUs. Note: The recommendations given are not inflexible rules; they are a starting point. Appropriate testing should be done to determine the correct settings for your scenario.
Tuning the Thread Pool for Burst Load Scenarios
If your application experiences unusually high loads of users in small bursts (for example, 1000 clients all logging in at 9 A.M. in the morning), your system may be unable to handle the burst load. Consider setting
minWorkerThreads and
minIOThreads as specified in Knowledge Base article 810259, "FIX:
SetMinThreads and
GetMinThreads API Added to Common Language Runtime
ThreadPool Class," at http://support.microsoft.com/default.aspx?scid=kb;en-us;810259.
Tuning the Thread Pool When Calling COM Objects
ASP.NET Web pages that call single-threaded apartment (STA) COM objects should use the ASPCOMPAT attribute. The use of this attribute ensures that the call is executed using a thread from the STA thread pool. However, all calls to an individual COM object must be executed on the same thread. As a result, the thread count for the process can increases during periods of high load. You can monitor the number of active threads used in the ASP.NET worker process by viewing the Process:Thread Count (aspnet_wp instance) performance counter.
The thread count value is higher for an application when you are using ASPCOMPAT attribute compared to when you are not using it. When tuning the thread pool for scenarios where your application extensively uses STA COM components and the ASPCOMPAT attribute, you should ensure that the total thread count for the worker process does not exceed the following value.
75 +
((maxWorkerThread +
maxIoThreads) * #CPUs * 2)
Evaluating the Change
To determine whether the formula for reducing contention has worked, look for improved throughput. Specifically, look for the following improvements:
* CPU utilization increases.
* Throughput increases according to the ASP.NET Applications\Requests/Sec performance counter.
* Requests in the application queue decrease according to the ASP.NET Applications\Requests In Application Queue performance counter.
If this change does not improve your scenario, you may have a CPU-bound scenario. In a CPU-bound scenario, adding more threads may increase thread context switching, further degrading performance.
When tuning the thread pool, monitor the Process\Thread Count (aspnet_wp) performance counter. This value should not be more than the following.
75 +
((maxWorkerThread +
maxIoThreads) * #CPUs)
If you are using
AspCompat, then this value should not be more than the following.
75 +
((maxWorkerThread +
maxIoThreads) * #CPUs * 2)
Values beyond this maximum tend to increase processor context switching.
More Information
For more information, see the following resources
* "ASP.NET Performance Monitoring, and When to Alert Administrators" by Thomas Marquardt, at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/monitor_perf.asp
* For more information about Web service scenarios, see Knowledge Base article 821268, "PRB: Contention, Poor Performance, and Deadlocks When You Make Web Service Requests from ASP.NET Applications," at http://support.microsoft.com/default.aspx?scid=kb;en-us;821268
* "At Your Service: Performance Considerations for Making Web Service Calls from ASPX Pages" at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service07222003.asp
* Microsoft Support
WebCast, "Microsoft ASP.NET Threading," at http://support.microsoft.com/default.aspx?scid=%2fservicedesks%2fwebcasts%2fen%2ftranscripts%2fwct060503.asp
* Knowledge Base article 827419, "PRB: Sudden Requirement for a Larger Number of Threads from the
ThreadPool Class May Result in Slow Computer Response Time," at http://support.microsoft.com/default.aspx?scid=kb;en-us;827419
* Knowledge Base article 810259, "FIX:
SetMinThreads and
GetMinThreads API Added to Common Language Runtime
ThreadPool Class," at http://support.microsoft.com/default.aspx?scid=kb;en-us;810259
Configure the Memory Limit
The memory threshold for ASP.NET is determined by the memoryLimit attribute on the <processModel> element in Machine.config. For example:
<processModel ... memoryLimit="60" .../>
This value controls the percentage of physical memory that the process is allowed to consume. If the worker process exceeds this value, the worker process is recycled. The default value shown in the code represents 60 percent of the total physical memory installed in your server.
This setting is critical because it influences the cache scavenging mechanism for ASP.NET and virtual memory paging. For more information, see "Configure the Memory Limit" in Chapter 6, "Improving ASP.NET Performance." The default setting is optimized to minimize paging. If you observe high paging activity (by monitoring the Memory\Pages/sec performance counter) you can increase the default limit, provided that your system has sufficient physical memory.
The recommended approach for tuning is to measure the total memory consumed by the ASP.NET worker process by measuring the Process\Private Bytes (aspnet_wp) performance counter along with paging activity in System Monitor. If the counter indicates that the memory consumption is nearing the default limit set for the process, it might indicate inefficient cleanup in your application. If you have ensured that the memory is efficiently cleaned but you still need to increase the limit, you should do so only if you have sufficient physical memory.
This limit is important to adjust when your server has 4 GB or more of RAM. The 60 percent default memory limit means that the worker process is allocated 2.4 GB of RAM, which is larger than the default virtual address space for a process (2 GB). This disparity increases the likelihood of causing an
OutOfMemoryException.To avoid this situation on an IIS 5 Web server, you should set the limit to the smaller of 800 MB or 60 percent of physical RAM for .NET Framework 1.0.
/3GB Switch
.NET Framework 1.1 supports a virtual space of 3 GB. If you put a /3GB switch in boot.ini, you can safely use 1,800 MB as an upper bound for the memory limit.
You should use the /3GB switch with only the following operating systems:
* Microsoft Windows Server™ 2003
* Microsoft Windows 2000 Advanced Server
* Microsoft Windows 2000 Datacenter Server
* Microsoft Windows NT 4.0 Enterprise Server
You should not use the /3GB switch with the following operating systems:
* Microsoft Windows 2000 Server
* Microsoft Windows NT 4.0 Server
Windows 2000 Server and Windows NT 4.0 Server can only allocate 2 GB to user mode programs. If you use the /3GB switch with Windows 2000 Server or Windows NT 4.0 Server, you have 1 GB for kernel and 2 GB for user mode programs, so you lose 1 GB of address space.
IIS 6
For IIS 6 use the Maximum used memory (in megabytes) setting in the Internet Services Manager on the Recycling page to configure the maximum memory that the worker process is allowed to use. As Figure 17.12 shows, the value is in megabytes and is not a percentage of physical RAM.
{Insert figure: CH17 – Memory Recycling.gif}
Figure 17.12
Memory recycling settings in the IIS 6 manager
More Information
For more information, see the following resources:
* For more information about running ASP.NET 1.1 with IIS 6, see the Microsoft ASP.NET FAQ page at
http://www.asp.net/faq/AspNetAndIIS6.aspx. * For more information about virtual address space and virtual memory paging activities, see Chapter 6, "Evaluating Memory and Cache Usage" in Part 2 of the Windows 2000 Operations Guide at http://www.microsoft.com/resources/documentation/windows/2000/server/reskit/en-us/serverop/part2/sopch06.mspx.
Configure Timeouts Aggressively
The following list explains the configuration settings that you can tune in respect to timeouts:
* executionTimeout. This is an attribute of the <httpRuntime> element with a default value of 90 seconds. You can programmatically set this attribute using
HttpServerUtility.ScriptTimeout as follows:
<httpRuntime executionTimeout="90" />
You need to change the default values if your application performs long-running operations like transferring large files, making long-running calls, or performing any other operation that may take longer than 90 seconds. Consider the following guidelines when deciding to change this attribute value:
* Clients of an average Web application expect a response in 7 to 10 seconds. Consider reducing the value of executionTimeout to deliberately time out excessively long-running requests and display an error message to users.
* Carefully evaluate any decision to increase the value of executionTimeout. Some scenarios, such as transferring extremely large files, may warrant increasing the value of this attribute. However, keep in mind the issue of user interface responsiveness and consider whether the user is willing to wait for a response for such a long time.
Longer timeouts result in server resources being retained for longer periods, which might cause stress and instability on the server under high load conditions.
In scenarios where you do need to increase executionTimeout to more than 180 seconds, you need to increase the value of the
responseDeadlockInterval attribute to a value greater than 180 seconds (its default value).
You should also make sure that executionTimeout is set to a value greater than the timeout value specified by the client on the Web service proxy. If the request for a Web page times out before the call to the Web service that was made from the page, you can end up with open socket connections, causing a resource leak.
The ASP.NET pages calling Web services can set a
TimeOut property on the proxy object. This timeout value should be less than the executionTimeout value, which in turn should be less than the
responseDeadlockInterval value. The value executionTimeout on a server hosting ASP.NET pages should be greater than on the server hosting your Web service. This setting handles the condition where a long-running Web service completes successfully, but the ASP.NET page returns a
ThreadAbortException. Note: Timeout values are specified in milliseconds. If you have debug=”false” in the Web.config file, the executionTimeout value will be ignored.
For more information about tuning the timeouts in relation to Web service proxies, see "Timeouts" in Chapter 10, "Improving Web Services Performance."
*
responseDeadlockInterval. This attribute is used by ASP.NET to detect deadlock or thread contention on the server. For example:
<processModel responseDeadlockInterval="00:03:00" />
Avoid increasing this timeout limit, because doing so may have an adverse effect on the overall performance of your application. For alternative solutions, see "Avoid Blocking on Long-Running Tasks" in Chapter 6, "Improving ASP.NET Performance."
* Worker process timeouts. The <processModel> element contains timeout, idleTimeout, shutdownTimeout, and
responseDeadlockInterval attributes. The timeout and idleTimeout attributes are set to infinite by default. Avoid changing these to lower values. Doing so causes the process to recycle (when the set threshold is reached), which is expensive and time-consuming and causes application downtime.
Evaluate Configuring
RequestQueueLimitThere is a named pipe between IIS and the ASP.NET worker process over which requests for ASP.NET are queued. There is also a queue for each virtual directory.
The default limit for the queue at the process level is 5000 and is specified by the
requestQueueLimit attribute on the <processModel> element as follows.
<processModel enable="true" requestQueueLimit="5000" />
The number of current requests is measured by ASP.NET\Requests Current. If the number of current requests (which includes the requests that are queued, executing, or waiting to be written to the client) exceeds the value set for
requestQueueLimit, the worker process rejects the requests with a 503 status code and the message "Server Too Busy."
The default limit for the queue for each virtual directory (or application) is 100. This limit is specified by the
appRequestQueueLimit attribute on the
<httpRunTime> element in Machine.config.
When the number of current requests in the application queue (measured by ASP.NET Applications\ Requests In Application Queue) exceeds the default threshold settings for each virtual directory, users receive a 503 status code and a “Server Too Busy” error message. Requests are rejected when the number of requests exceeds the
appRequestQueueLimit value in Machine.config:
The default value for the process queue is optimized. It should be roughly the value of the
appRequestQueueLimit attribute multiplied by the total number of virtual directories.
Note: A bug in .NET Framework version 1.1 allowed ASP.NET to handle an infinite number of requests when running in IIS 6.0. The fix, available in "821156 INFO: ASP.NET 1.1 June 2003 Hotfix Rollup Package" at http://support.microsoft.com/?id=821156, causes ASP.NET to reject requests when the value of Requests Current exceeds the value of
requestQueueLimit. The default value of 100 for
appRequestQueueLimit (per virtual directory) is low for servers with only a few applications (or a single application). You should consider increasing the value incrementally and measure the application performance (throughput, response time, and so on) at the point where requests start being rejected. The response time for the queued requests should not exceed the levels defined by your application's performance objectives. If it does, it probably means that the requests are waiting too long in the queue to be processed, so increasing the queue limit will not serve any purpose.
The
requestQueueLimit value should be set higher than the sum of the
appRequestQueueLimit values for all virtual directories because the
requestQueueLimit value is actually the limit for total number of requests queued, executing, and waiting to be written to the clients for all virtual directories combined.
Disable Tracing and Debugging
Disable tracing and debugging in the Machine.config and Web.config as follows.
<configuration>
<system.web>
<trace enabled="false" pageOutput="false" /?
<compilation debug="false" />
</system.web>
</configuration>
For more information, see Knowledge Base article 815157, "HOW TO: Disable Debugging for ASP.NET Applications" at http://support.microsoft.com/default.aspx?scid=kb;en-us;815157.
Note: You may also want to check that tracing and debugging is not enabled on individual pages, because those settings will override the settings in the Web.config.
Disable Session State If You Do Not Use It
If you are not using sessions, you should turn them off. By turning them off, you prevent the ASP.NET process from creating and maintaining session objects on a per-user basis. You can turn off the session state for an individual application by setting the mode attribute to "off" on the <sessionState> element in Web.config as follows.
<sessionstate mode="off" />
For more information, see "Session State" in Chapter 6, "Improving ASP.NET Performance."
If You Use Session State, Then Reduce Timeouts
User information is stored in session state until the session expires (the default is 20 minutes). If the client disconnects, the session continues to remain active, and session state continues to consume resources until it times out. Reducing the session state helps clean up unused sessions faster. Reducing session state is also good practice from a security standpoint.
You can change the timeout values in your application's Web.config file by modifying the timeout attribute on the <sessionState> element. The default setting of 20 minutes is shown in the following code.
<sessionState timeout="20"/>
Evaluating the Change
If you set the session state timeout to too low a value, your users may experience having their sessions expire frequently, which would increase the redundant hits to the site for the same requests as well as user dissatisfaction. If you set the timeout to too high a value, server resources are consumed for long periods, which affects your application scalability.
You need to optimize session timeout values. For information about how to identify the optimum value for session timeouts, see "Sessions" in "ASP.NET" in Chapter 15, "Measuring .NET Application Performance."
Disable View State If You Do Not Need It
There are a number of ways to disable view state at various levels:
* To disable view state for all applications on a Web server, configure the <pages> element in Machine.config as follows.
<pages enabledViewState="false" />
This approach allows you to selectively enable view state just for those pages that need it using the
EnableViewState attribute of the @ Page directive.
* To disable view state for a single page, use the @ Page directive as follows.
<%@ Page EnableViewState="false" %>
* To disable view state for a single control on a page, set the control's
EnableViewState property to false as follows.
//programatically
yourControl.EnableViewState = false;
//something
<asp:datagrid
EnableViewState=”false” runat=”server” />
More Information
For more information, see "View State" in Chapter 6, "Improving ASP.NET Performance."
If You Upload Large Files, Consider
maxRequestLengthIf your application needs to upload large files, be aware that the default setting does not allow anything greater than 4 MB. To change this default, configure the
maxRequestLength attribute on the <httpRuntime> element in Machine.config to an appropriate value.
More Information
For more information, see Knowledge Base article 295626, "PRB: Cannot Upload Large Files When You Use the
HtmlInputFile Server Control," at http://support.microsoft.com/default.aspx?scid=kb;en-us;295626.
Consider Web Gardens for Scenarios that Benefit from Processor Affinity
You might need to consider Web gardens if your application uses STA components excessively or it uses any other technique which might benefit from affinity to a processor. Affinity to a particular processor helps the process takes advantage of more frequent CPU cache (L1 or L2 cache) hits.
You should always test and evaluate whether Web gardens improve performance for your scenario. They are not generally advocated as an option for most applications.
By default, on an IIS 5 Web server there is only one ASP.NET worker process. You can set the webGarden attribute on the <processModel> element in Machine.config to true to create multiple worker processes; one per eligible processor on a multiple processor server.
You can specify the eligible processors by setting the cpuMask attribute. This attribute specifies a bit pattern that indicates the
CPUs eligible to run ASP.NET threads. For example, the cpuMask hexadecimal value 0x0d represents the bit pattern 1101. On a server with four processors, this bit pattern indicates that ASP.NET processes can be scheduled for
CPUs 0, 2, and 3, but not CPU 1. If webGarden is set to true, by default, all
CPUs are enabled and ASP.NET starts one process for each CPU. If webGarden is set to false, the cpuMask attribute is ignored and only one worker process runs on the server.
The default values for these attributes are shown below.
<processModel webGarden="false" cpuMask="0xffffffff" />
Requests are distributed among the multiple processes on a round-robin basis. Each process has an affinity to a particular processor in this case.
On an IIS 6.0 Web server, you can create multiple worker processes per application pool, which can have affinity to particular processors.
If you are considering using Web gardens, you should be aware of the following pitfalls:
* Cache, session, and application state are not shared among the different processes. Hence, each process needs its own copy of cache and application state. You can store the session state out of process in a state service or SQL Server database to share it across processes. Out-of-process session state incurs the additional overhead of serialization and cross-process or cross-server communication.
* Memory requirements for your server increase when you use Web gardens because multiple processes are used.
More Information
For more information about Web gardens, the scenarios where they might result in performance gains, and IIS 6.0 deployment considerations, see "Deployment Considerations" in Chapter 6, "Improving ASP.NET Performance" and "Web and Application Server Infrastructure — Performance and Scalability" at http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/webapp/iis/iis6perf.mspx.
Additional Considerations
In addition to the primary tuning options for ASP.NET applications discussed earlier, you also have the following additional considerations:
* Tuning for pages and compilation. ASP.NET compiles all of the pages in a directory into a single assembly when the first page is requested. This feature, referred to as batch compilation, is beneficial because in general fewer assemblies are preferable. If you have several hundred pages in a directory, the first request for a page may take a long time to execute due to the amount of compilation work needed.
The timeout for batch compilation is specified by the batchTimeout attribute on the <compilation> element. If this value is exceeded, batch compilation continues on a background thread and the requested page is compiled individually.
You are not advised to modify the default batchTimeout setting. Instead, you should design your application to avoid using an excessive number of pages. For example, consider using fewer dynamic pages that vary their behavior by using query strings, rather than using large numbers of static pages.
* Short circuiting the HTTP pipeline. User requests travel through various modules specified in the HTTP pipeline. These are defined in Web.config and Machine.config. By removing modules that your application does not use, you avoid any unnecessary overhead introduced by the modules. Measure to see if this performance gain is significant for your application.
For example, if your Web application does not use forms authentication, you can remove the
FormsAuthentication module by adding the following entry to Web.config.
<httpModules>
<remove name="FormsAuthentication" />
</httpModules>
Return to
HomePage