IIS 7.x improves internal compression functionality
dramatically making it much easier than previous versions to take advantage of
compression that's built-in to the Web server. IIS 7.x also supports dynamic
compression which allows automatic compression of content created in your own
applications (ASP.NET or otherwise!). The scheme is based on content-type
sniffing and so it works with any kind of Web application framework.
There are two approaches available here:
- Static Compression
Compresses static content from the hard disk. IIS can cache this content by
compressing the file once and storing the compressed file on disk and serving
the compressed alias whenever static content is requested and it hasn't
changed. The overhead for this is minimal and should be aggressively enabled.
- Dynamic Compression
Works against application generated output from applications like your
ASP.NET apps. Unlike static content, dynamic content must be compressed every
time a page that requests it regenerates its content. As such dynamic
compression has a much bigger impact than static caching. Before you read this
tutorial, I would recommend you to read this
documentation how to setup dynamic compression in IIS 7.
How Compression is
configured
Compression in IIS 7.x is configured with two .config
file elements in the <system.WebServer> space. The elements can be set
anywhere in the IIS/ASP.NET configuration pipeline all the way from
ApplicationHost.config down to the local web.config file. The following is from
the the default setting in ApplicationHost.config (in the
%windir%\System32\inetsrv\config forlder) on IIS 7.5 with a couple of small
adjustments (added json output and enabled dynamic compression):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpCompression
directory="%SystemDrive%\inetpub\temp\IIS
Temporary Compressed Files">
<scheme
name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="9" />
<dynamicTypes>
<add
mimeType="text/*" enabled="true" />
<add
mimeType="message/*" enabled="true" />
<add
mimeType="application/x-javascript"
enabled="true" />
<add
mimeType="application/json" enabled="true" />
<add
mimeType="*/*" enabled="false" />
</dynamicTypes>
<staticTypes>
<add
mimeType="text/*" enabled="true" />
<add
mimeType="message/*" enabled="true" />
<add
mimeType="application/x-javascript"
enabled="true" />
<add
mimeType="application/atom+xml"
enabled="true" />
<add
mimeType="application/xaml+xml"
enabled="true" />
<add
mimeType="*/*" enabled="false" />
</staticTypes>
</httpCompression>
<urlCompression
doStaticCompression="true" doDynamicCompression="true" />
</system.webServer>
</configuration>
You can find documentation on the httpCompression and
urlCompression keys here respectively:
http://msdn.microsoft.com/en-us/library/ms690689%28v=vs.90%29.aspx
http://msdn.microsoft.com/en-us/library/aa347437%28v=vs.90%29.aspx
What is
httpCompression and How it works
Basically httpCompression
configures what types to compress and how to compress them. It specifies the
DLL that handles gzip encoding and the types of documents that are to be
compressed. Types are set up based on mime-types which looks at returned
Content-Type headers in HTTP responses. For example, I added the
application/json to mime type to my dynamic compression types above to allow
that content to be compressed as well since I have quite a bit of AJAX content
that gets sent to the client.
How to Enables and
Disables Compression
The urlCompression element is a quick way to turn
compression on and off. By default static compression is enabled server wide,
and dynamic compression is disabled server wide. This might be a bit confusing
because the httpCompression element also has a doDynamicCompression attribute
which is set to true by default, but the urlCompression attribute by the same
name actually overrides it.
The urlCompression element only has three attributes:
doStaticCompression, doDynamicCompression and dynamicCompressionBeforeCache.
The doCompression attributes are the final determining factor whether
compression is enabled, so it's a good idea to be explcit! The default for
doDynamicCompression='false”, but doStaticCompression="true"!
How Static
Compression Works
Static compression works against static content loaded from
files on disk. Because this content is static and not bound to change
frequently – such as .js, .css and static HTML content – it's fairly easy for
IIS to compress and then cache the compressed content. The way this works is
that IIS compresses the files into a special folder on the server's hard disk
and then reads the content from this location if already compressed content is
requested and the underlying file resource has not changed. The semantics of
serving an already compressed file are very efficient – IIS still checks for
file changes, but otherwise just serves the already compressed file from the
compression folder.
Because static compression is very efficient in IIS 7 it's
enabled by default server wide and there probably is no reason to ever change
that setting. Dynamic compression however, since it's more resource intensive,
is turned off by default. If you want to enable dynamic compression there are a
few quirks you have to deal with, namely that enabling it in
ApplicationHost.config doesn't work. Setting:
<urlCompression doDynamicCompression="true" />
in applicationhost.config appears to have no effect and I
had to move this element into my local web.config to make dynamic compression
work. This is actually a smart choice because you're not likely to want dynamic
compression in every application on a server. Rather dynamic compression should
be applied selectively where it makes sense. However, nowhere is it documented
that the setting in applicationhost.config doesn't work (or more likely is
overridden somewhere and disabled lower in the configuration hierarchy).
So: remember to set doDynamicCompression=”true” in
web.config!!!
Dynamic Compression
By default dynamic compression is disabled and that's
actually quite sensible – you should use dynamic compression very carefully and
think about what content you want to compress. In most applications it wouldn't
make sense to compress *all* generated content as it would generate a
significant amount of overhead.
There are also a few settings you can tweak to minimize the
overhead of dynamic compression. Specifically the httpCompression key has a
couple of CPU related keys that can help minimize the impact of Dynamic
Compression on a busy server:
- dynamicCompressionDisableCpuUsage
- dynamicCompressionEnableCpuUsage
By default these are set to 90 and 50 which means that when
the CPU hits 90% compression will be disabled until CPU utilization drops back
down to 50%. Again this is actually quite sensible as it utilizes CPU power
from compression when available and falling off when the threshold has been
hit. It's a good way some of that extra CPU power on your big servers to use
when utilization is low. Again these settings are something you likely have to
play with. I would probably set the upper limit a little lower than 90% maybe
around 70% to make this a feature that kicks in only if there's lots of power
to spare. I'm not really sure how accurate these CPU readings that IIS uses are
as Cpu usage on Web Servers can spike drastically even during low loads. Don't
trust settings – do some load testing or monitor your server in a live
environment to see what values make sense for your environment.
Finally for dynamic compression I tend to add one Mime type
for JSON data, since a lot of my applications send large chunks of JSON data
over the wire. You can do that with the application/json content type:
<add mimeType="application/json" enabled="true" />
Conclusion
In summary IIS 7 makes GZip easy finally, even if the
configuration settings are a bit obtuse and the documentation is seriously
lacking. But once you know the basic settings I've described here and the fact
that you can override all of this in your local web.config it's pretty straight
forward to configure GZip support and tweak it exactly to your needs.
Static compression is a total no brainer as it adds very
little overhead compared to direct static file serving and provides solid
compression. Dynamic Compression is a little more tricky as it does add some
overhead to servers, so it probably will require some tweaking to get the right
balance of CPU load vs. compression ratios. Looking at large sites like Amazon,
Yahoo, NewEgg etc. – they all use