Click here to Skip to main content
Click here to Skip to main content

Making the most out of IIS compression - Part 1: Configuring IIS 7 compression

, 24 Aug 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
In this two part series, I'll show how to get the most out of the compression features built into IIS 7 and IIS 6. This first article focuses specifically on IIS 7.

Parts in this series

Introduction

Using compression is the single most effective way to reduce page load times. The .aspx files sent by the server to the browser consist of HTML. HTML is highly compressible by algorithms such as gzip. Because of this, modern web servers including IIS 5 and later have the ability to compress outgoing files, and modern browsers have the ability to decompress incoming files.

Both IIS 6 and IIS 7 offer advanced compression related options that help you get better performance improvements for your web site and make better use of your servers and bandwidth. Unfortunately, these options are not always easy to access. This article series shows step by step how to unlock these options.

In the first article in this two part series, we'll focus on configuring IIS 7 compression. If you are used to IIS 6, you'll find that IIS 7 offers many new features, including the ability to cache not only compressed static files, but also compressed dynamic files. If you still use IIS 6, the next article in the series will show how to configure IIS 6 compression.

This article is based on chapter 10 Compression of my book ASP.NET Site Performance Secrets.

If you like this article, please vote for it.

Contents

Request and response headers involved in compression

How does the server know that the browser can accept compressed content? And how does the browser know that the content it received is compressed?

When a browser that supports compression sends a request to the server, it includes the request header Accept-Encoding telling the server which compression algorithms it supports. For example:

Accept-Encoding: gzip,deflate

If the server then uses compression for its response, it includes the response header Content-Encoding in the (uncompressed) file header to say how the file has been compressed, as shown:

Content-Encoding: gzip

This keeps the browser and server compression-wise in sync. However, it isn't only browsers and servers that send and receive requests and responses, but proxies as well. And proxies can cache responses and serve subsequent requests from their cache. When a proxy caches a compressed file, how do we make sure that the proxy doesn't send that compressed file to a browser that can't process compressed files?

The solution adopted by IIS 6 and IIS 7 is to tell the proxy that if it receives a request without the Accept-Encoding request header, it must not serve a file that was sent in response to a request that did have the Accept-Encoding request header, or vice versa, that is, the Accept-Encoding request headers must match. IIS 6 and 7 make this happen by sending a Vary header in the response from the server when compression is enabled as shown:

Vary: Accept-Encoding

IIS 6 also lets you override the Cache-Control and Expires headers for compressed files via properties in its metabase. This allows you to suppress proxy caching for compressed files. The IIS 6 metabase will be described in part 2, about configuring IIS 6 compression. The metabase properties that override the Cache-Control and Expires headers can be found here.

Starting configuration of IIS 7 compression

Before you start configuration of IIS 7 compression, find out at the following sites whether your pages already use compression, and if so, how much bandwidth you're saving:

Enabling compression in IIS 7 essentially consists of these steps:

  1. Installing the dynamic content compression module;
  2. Enabling compression;
  3. Configuring advanced features.

Let's go through these steps one by one.

Installing the dynamic content compression module

If you want to use compression for dynamic files, first install the dynamic content compression module. The steps to do this are different depending on whether you use Vista/Windows 7 or Windows Server 2008.

On Windows Server 2008:

  1. Click Start | Administrative Tools | Server Manager.
  2. On the left-hand side, expand Roles and then click on Web Server (IIS).
  3. Scroll down to the Role Services section and then click on Add Role Services. The Add Role Services wizard opens:
  4. On the Select Role Services page, scroll down to the Performance section and select Dynamic Content Compression. Click on Next.
  5. Read the message and click Install.
  6. Once the installation is done, close the wizard.

On Vista or Windows 7:

  1. Click on Start | Control Panel | Programs | Turn Windows features on or off. The Windows Features dialog opens.
  2. Expand Internet Information Services, expand World Wide Web Services, and expand Performance Features. Select Http Compression Dynamic.
  3. Click on OK. Wait for the feature to be configured.

Enabling compression

Now enable compression in the IIS Manager:

  • Open IIS Manager. Click on Start | Control Panel. Type admin in the search box. Click on Administrative Tools. Double-click on Internet Information Services (IIS) Manager.
  • Click on your machine. Then double-click on the Compression icon on the right-hand side.
  • The compression window opens. Here you can enable compression for dynamic content and static content. The window shows the following items:
    • Enable dynamic content compression: Unless your server already uses a lot of CPU, you will want to enable dynamic content compression.
    • Enable static content compression: You can safely enable static content compression because compressed static content gets cached. So, only the initial compression takes CPU cycles.
    • Only compress files larger than (in bytes): It makes sense to not compress small files. Because compression produces some overhead in the file, compressing a small file may actually make it bigger rather than smaller.
    • Cache directory: This is where compressed static files are stored. If you are short on disk space on the system drive, consider putting this on another drive. Make sure that the drive is a local drive or NTFS partition, and that it isn't compressed or shared.
    • Per application pool disk space limit (in MB): If you have lots of application pools and limited disk space, you may want to adjust this. If you have 100 application pools and you leave this at 100MB, 100 x 100MB = 10GB may be used to cache static compressed files.
  • On the right-hand side of the window, click on Apply. Compression is now enabled.

Setting compression by site, folder, or file

In addition to enabling or disabling compression for all sites on the server, you can enable or disable compression at a site level, or even a folder or file level.

To make this work:

  1. Open the IIS Manager and in the left-hand side, click on the site, folder, or file whose compression status you want to change.
  2. Make sure that the middle pane is switched to Features View, and double-click on the Compression icon.
  3. This will open a window where you can enable or disable compression for dynamic or static files:

Compression level

You can tweak the tradeoff between compression and CPU usage by setting the compression level. The higher the compression level, the greater the compression and CPU usage.

The compression level can be set separately for static and dynamic files. For static files, use 9, the highest level. For dynamic files, compression level 4 seems to be the sweet spot, as shown in this study.

However, the optimal compression level for your website may be different, depending on how much spare CPU capacity you have, the compressibility of your pages, and your bandwidth costs. Experiment with different levels to see which one works best for you.

To set the compression level:

  1. Execute this from the command prompt:
  2. C:\Windows\System32\Inetsrv\Appcmd.exe
      set config -section:httpCompression 
      -[name='gzip'].staticCompressionLevel:9 
      -[name='gzip'].dynamicCompressionLevel:4

    (This sets compression level 9 for static files and compression level 4 for dynamic files).

  3. Reset the IIS server to make the new compression level take effect. In IIS Manager, click on the server at the top of the tree and then click on Restart on the right-hand side.

Disabling compression based on CPU usage

To make sure that compression doesn't overload the CPU, IIS 7 calculates average CPU usage every 30 seconds. It automatically switches off compression when CPU usage exceeds a given limit. Then when CPU usage drops below a second limit, it switches on compression again.

The default values for these limits are:

Switch compression off at (CPU usage) Switch back on at (CPU usage)
Dynamic files 90 percent 50 percent
Static files 100 percent 50 percent

Note that this means that if CPU usage on your server is consistently over 50 percent, and when it spikes over 90 percent, compression for dynamic files will be switched off, but will never be switched back on again.

You can change these limits by modifying the applicationHost.config file, which is normally in the folder C:\Windows\System32\inetsrv\config:

  1. Make a backup copy of applicationHost.config.
  2. Open applicationHost.config with a text editor.
  3. Find the <httpCompression> section.
  4. To change the CPU usage at which compression for dynamic files is switched back on to 70 percent, add the dynamicCompressionEnableCpuUsage attribute to the httpCompression element, as shown:
  5. <httpCompression dynamicCompressionEnableCpuUsage="70" .... >

    Note that you provide a number to the attribute, not a percentage, so don't write a percentage sign when setting the attribute. The value 70 shown here is simply an example, not a recommendation. You need to determine the optimal value for your own site.

  6. Save the applicationHost.config file.
  7. Reset the IIS server to make the new compression level take effect. Start IIS Manager, click on the server at the top of the tree, and then click on Restart on the right-hand side.

In case you want to change any of the other limits, here are the matching attributes:

Switch compression off at (CPU usage) Switch back on at (CPU usage)
Dynamic files dynamicCompressionDisableCpuUsage dynamicCompressionEnableCpuUsage
Static files staticCompressionDisableCpuUsage staticCompressionEnableCpuUsage

If you want to stop IIS from ever switching off compression based on CPU usage, set all these attributes to 100.

You will find all the elements and attributes that can be used with httpCompression here.

Setting the request frequency threshold for static compression

As you saw earlier, IIS 7 caches the compressed versions of static files. So, if a request arrives for a static file whose compressed version is already in the cache, it doesn’t need to be compressed again.

But what if there is no compressed version in the cache? Will IIS 7 then compress the file right away and put it in the cache? The answer is yes, but only if the file is being requested frequently. By not compressing files that are only requested infrequently, IIS 7 saves CPU usage and cache space.

By default, a file is considered to be requested frequently if it is requested two or more times per 10 seconds. This is determined by two attributes in the serverRuntime element in web.config:

serverRuntime attribute Description
frequentHitThreshold Number of times a URL must be requested within the time span specified in the frequentHitTimePeriod attribute to be considered frequently hit. Must be between 1 and 2147483647. Default is 2.
frequentHitTimePeriod Time interval in which a URL must be requested the number of times specified in the frequentHitThreshold attribute before it is considered to be frequently hit. Default is 10 seconds.

This means that when a static file is requested for the very first time, it won’t be compressed.

For example, to specify that static files need to be hit seven times per 15 seconds before they will be compressed, use:

<configuration>
...
  <system.webServer>
    <serverRuntime frequentHitThreshold="7" frequentHitTimePeriod="00:00:15" />
  </system.webServer>
...
</configuration>

Caching compressed dynamic files

You've seen that IIS 7 caches only the compressed version of static files, and that dynamic files are compressed for each request (provided that dynamic file compression is enabled). This means that compressing dynamic files takes much more CPU than static files.

That makes sense if the dynamic files are different for each visitor, for example, if each page contains personal information. However, if the dynamic pages are fairly static and the same for all visitors, it makes sense to cache their compressed versions too.

You may already use the ASP.NET OutputCache directive to cache your .aspx pages. The issue is that by default, IIS stores the uncompressed version of the file in the output cache, rather than the compressed version. For each request, IIS then has to compress the contents of the cache before sending it to the browser. This is not very efficient.

Storing compressed files in the output cache

Here is how to get IIS to cache the compressed version of the file, rather than the uncompressed version. That way, it doesn't have to compress the file for each request, reducing CPU usage.

Because this uses ASP.NET output caching, you need to use the OutputCache directive in your pages, as shown:

<%@ OutputCache Duration="300" VaryByParam="none" %>

This caches the page for 300 seconds.

Now to get IIS to cache the compressed version rather than the uncompressed version, modify the applicationHost.config file. You'll normally find this file in the folder C:\Windows\System32\inetsrv\config:

  1. Make a backup copy of applicationHost.config.
  2. Open applicationHost.config with a text editor.
  3. Find the <urlCompression> section.
  4. Add the dynamicCompressionBeforeCache="true" attribute to the urlCompression element, as shown:
  5. <urlCompression dynamicCompressionBeforeCache="true" ...  />
  6. Save the applicationHost.config file.
  7. Reset the IIS server to make the new attribute take effect.
  8. Start IIS Manager, click the server at the top of the tree, and then click Restart on the right-hand side.

What if a client doesn't accept compressed content?

Now that we're caching compressed content, what happens if someone visits your site with a browser that doesn't accept compressed content?

To simulate this eventuality, let's send a request to the server that doesn't have the Accept-Encoding request header. This should force the server to send uncompressed content.

To do this, we'll use Fiddler, a free proxy which allows you to "fiddle" with requests and responses while they are travelling between browser and server. It's easiest to do this with Firefox:

  1. Open Firefox and download Fiddler at http://www.fiddler2.com/fiddler2/.
  2. Install Fiddler and start it.
  3. On the Firefox status bar, switch on forcing traffic to Fiddler.
  4. At this stage, when you visit a page with Firefox, the server should still use compression (assuming the request has an Accept-Encoding request header allowing gzip compression).
  5. You can measure the actual size of your compressed pages as they will travel over the Internet to the browser using the Web Developer add-on for Firefox:

    1. Using Firefox, visit http://chrispederick.com/work/web-developer to download and install the Web Developer add-on.
    2. After you have installed Web Developer, load the page again.
    3. Right click anywhere in the page. A popup menu will appear. Click Web Developer | Information | View Document Size. A new window appears showing the groups of files making up the page.
    4. Expand the Documents group to see the size of the page. If it was compressed while travelling over the Internet, you will also see its compressed size.
  6. Now get Fiddler to strip off the Accept-Encoding request header from the request going from Firefox to the web server. In the Fiddler window on the right-hand side, click on the Filters tab, select Use Filters, select Delete request header, and type in Accept-Encoding.
  7. Refresh the page in Firefox. Check the file size again with Web Developer. You should find that no compression was used with this request. That will make browsers that do not support compression happy. So far, so good.
  8. In Fiddler, uncheck the Delete request header checkbox. As a result, the Accept-Encoding request header now makes it to the web server again.
  9. Refresh the page. The server should now compress the file again. But if you check with Web Developer, you'll find that it is still sending files uncompressed!
  10. This is because when IIS received the request for uncompressed content, it threw away the compressed contents in the cache, regenerated the content, and stored it uncompressed in the cache. It then keeps serving this uncompressed content until the cache expires, even to clients that accept compressed content.

  11. You can prevent this from happening by caching both compressed and uncompressed content. You do that by including VaryByContentEncoding in the OutputCache directive, as shown in the following code:
  12. <%@ OutputCache Duration="300" VaryByParam="none" 
        VaryByContentEncoding="gzip;deflate" %>
  13. If you now delete the Accept-Encoding header and then let it go through again, you'll see that the server always sends compressed content to clients that accept it, even if another client didn't accept it.
  14. Before you end this experiment and close Fiddler, go back to the Firefox status bar and stop sending traffic to Fiddler. Otherwise Firefox will complain about the missing proxy when you close Fiddler.

A drawback of using VaryByContentEncoding in the OutputCache directive is that it disables kernel caching for this file. Kernel caching is a highly efficient form of server side caching, and is discussed in Chapter 5 of my book ASP.NET Site Performance Secrets.

So should you use VaryByContentEncoding in the OutputCache directive? Seeing that you are reading this chapter, the gain in compression by using VaryByContentEncoding may well outweigh the loss of kernel caching, especially seeing that you already use output caching. Your best bet would be to try both scenarios in production for a while, and compare CPU usage, response times, and bandwidth used per request for each scenario.

Improving the compressibility of your pages

If your server uses compression, then it makes sense to optimize compressibility of your .aspx, JavaScript, and CSS files. Compression algorithms like repeating content, which puts a premium on consistency:

  • Always specify HTML attributes in the same order. One way to achieve this is to have all your HTML generated by high-level web controls and custom server controls, instead of low level HTML server controls. This will slightly increase CPU usage, but will give you assured consistency. For example, write the following:
  • <asp:Hyperlink runat="server"......>

    Instead of:

    <a runat="server"......>
  • Likewise, within CSS selectors, write your properties in alphabetical order.
  • Use consistent casing. Use all lowercase for HTML tags and attributes, and you'll be XHTML compliant as well.
  • Use consistent quoting: Don't mix "...." and '....'.

Summary

In this article, we saw how to configure compression on IIS 7, including its more advanced, lesser known features. In the next article, I'll show how to get the most out of the compression features built into IIS 6.

If you enjoyed this series and want to know the full story on how to improve ASP.NET site performance, from database server to web server to browser, consider my book ASP.NET Site Performance Secrets. Or visit my web site ASP.NET Performance.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Matt Perdeck
Web Developer
Australia Australia
Twitter: @MattPerdeck
Blog: mattperdeck.com
Current project: JSNLog JavaScript Logging Package
 
Matt has over 6 years .NET and SQL Server development experience. Before getting into .Net, he worked on a number of systems, ranging from the largest ATM network in The Netherlands to embedded software in advanced Wide Area Networks and the largest ticketing web site in Australia. He has lived and worked in Australia, The Netherlands, Slovakia and Thailand.
 
He recently wrote a book, ASP.NET Performance Secrets (www.packtpub.com/asp-net-site-performance-secrets/book) in which he shows in clear and practical terms how to quickly find the biggest bottlenecks holding back the performance of your web site, and how to then remove those bottlenecks. The book deals with all environments affecting a web site - the web server, the database server and the browser.
 
Matt currently lives in Sydney, Australia. After 2 years at Readify, he now works at the global professional services company PwC. His current contract ends at 29 June 2014.
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionSetting up compression site by site PinmemberMauricio Dominguez10-Feb-14 10:05 
GeneralMy vote of 5 Pinmembereng_george113-Feb-13 4:05 
GeneralMy vote of 5 PinmemberSimlariss11-Dec-12 20:54 
GeneralMy vote of 5 PinmemberPeterJ32125-Oct-12 19:34 
GeneralMy vote of 5 Pinmembermtapiero29-Feb-12 3:36 
GeneralMy vote of 5 PinmemberSebastien Lorion18-Aug-11 7:46 
GeneralMy vote of 5 PinmemberSrinivasan Raj18-Aug-11 2:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141015.1 | Last Updated 24 Aug 2011
Article Copyright 2011 by Matt Perdeck
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid