Tweaking .NET Machine.Config For Production Deployments

September 17, 2008

I recently rolled out an enterprise wide app to a pilot group (which, since pilots are silly or so I’m told, that means we rolled it out to EVERYONE or ~1200 users).  Not a huge amount by any means, but without a pilot, we didn’t have a good baseline to gauge performance settings.

I remember reading an article by Peter Bromberg ages ago about tuning IIS 6.0.  After a bit of Googling, I found it again and, one-by-one, started tweaking various settings on our development environment and hitting it with 500–1000 concurrent load users.

Here’s what I came up with that seemed to give the best bang for the buck.

  <system.net>

    <connectionManagement>
      <add address=”*” maxconnection=”100″ />
    </connectionManagement> 

  </system.net>

maxconnections – This sets how many outgoing connections the ASP.NET service can make FROM the server, such as to databases, web services, etc.  Increasing this can increase the number of concurrent connections are available to your application.

  <system.web>

    <deployment retail=”true” />

    <processModel
                autoConfig=”true”
                memoryLimit=”75″
                maxIoThreads=”100″
                minIoThreads=”30″
                minWorkerThreads=”40″
                maxWorkerThreads=”100″
                clientConnectedCheck=”00:00:05″ />

    <httpRuntime
                minFreeThreads=”352″
                minLocalRequestFreeThreads=”308″
                enableKernelOutputCache=”false”
                maxRequestLength=”10240″ />  

  </system.web>

deployment/retail – Setting retail=”true” essentially forces all web applications on that machine to compile without debug.  This is extremely helpful for those rare cases that you forget to set debug=”false” on a web project.  In a production environment, debug files should rarely/never be needed, so this blankets the server.

processModel/autoConfig – autoConfig sets everything to the defaults except what I explicitly set below.  Just at time saver.

processModel/memoryLimit – This is a percentage of how much memory a web process can consume before it splits off into another process.  Since our production servers ONLY run IIS and web servers, then it should be safe to set this to 75% of the total memory on the box.

processModel/maxIoThreads – Based on Bromberg’s recommendation, this controls how many IO threads are allowed to the web process.  minIoThreads is the other side of the scale.

processModel/maxWorkerThreads – Based on Bromberg’s recommendation, this controls how many worker threads are in the pool for each web process.  minWorkerThreads is the other side of the scale.

processModel/clientConnectedCheck – An excellent setting that tells the server to check every 5 seconds to see if the client is connected.  If not, trash their queued requests (since they’re not there to receive it anymore).  According to this source, this also helps for those situations where users get “impatient” and machine-gun click the mouse trying to get a response.

httpRuntime/minFreeThreads – Based on Bromberg’s recommendation, a setting that tells the machine what the minimum number of threads in the pool must be in order for incoming requests to be processed.

httpRuntime/minLocalRequestFreeThreads – Same as the prior, but for the local machine (localhost)—good for locally hosted web servers; however, I’m not sure if it’s smart enough to know if “localhost” and a registered DNS entry are the same (I never refer to a machine as localhost).  It’s set, but more research required here.

httpRuntime/enableKernelOutputCache – This is set to FALSE for me, though most everything recommends true.  Why?  Kernel Mode caching is great—it’s speedy and a good way to speed up pages; however, we’ve had several issues in the past (on IIS 6) where it caused sessions to “merge” across authenticated users.  The issue is described here in KB917072.  Setting this for the machine just solves the problem overall.  Honestly, unless I can guarantee a way that the sessions/cookies won’t cross, I’ll give up a few milliseconds of performance in the day to guarantee a user experience.

httpRuntime/maxRequestLength – The default request length is 4096K; however, for uploading large file into the system, that becomes the limit.  A few of our applications allows users to upload documents, PDFs, etc. and attach them—we need a larger limit.  ~10MB seems to work well.  You “could” set this in the web.config; however, we base our production server at 10MB and then ramp up from there.

As with all tweaks, your mileage may vary—as mine does every single day.  I’d be interested to hear of other tweaks for higher performing web sites as well as feedback on the above (especially if I misinterperted a setting and simply haven’t seen the failure yet).

  1. Deepak
    December 19, 2008 at 11:26 am

    Hi,

    I did similar changes for my Framework 1.1 based production server a few years back but now I am working on an enterprise application (5000+ users) and need to deploy to prod. Are there similar settings for framework 2.0/3.0/3.5?? What can i do on the box to increase throughput and make application perform better without tweaking app itself?

    Thanks

  2. December 21, 2008 at 11:17 am

    @Deepak-

    The settings in this post work for 2.0 -> 3.5 frameworks. Thankfully, quite a few remained the same between 1.1 and 2.0. Depending on the situation, I have many of these in place and have baselined the performance (with and without) and see a marked improvement.

  3. April 30, 2009 at 11:15 am

    So,

    What do you do, if you tweak machine config, and it has no effect (CPU Utilization is still high)?🙂

    • May 4, 2009 at 7:02 am

      @Mark-

      Can you nail down what’s causing the CPU utilization? A specific site, a line of code, etc? Usually when I see that in a site, I start parsing the site with ANTS Profiler (http://is.gd/wAzW) and see if I can find the line of code or method that’s causing the problem.

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: