Caching has always been one of my favorite areas. Although, I never attempted to look much into how various settings in IIS or HTTP affect caching, I always had it on my to do list which was pushed down the priority list for several months. Now, that I have a good break from my cases, I am spending some time deep diving into how caching works with IIS, specifically how HTTP Kernel mode caching and User mode caching in IIS can be exploited to get better performance from an IIS 6.0 web server.
Before I begin, I want to mention that there are many parameters that affect caching and all of it depends on what type of content is being served by IIS. Depending on what type of application you have (Static/ASP/ASP.net/PHP etc) you will need to first make decisions on what those settings are, that need to be tuned to increase performance. This has always been the question for most developers and web server administrators: What cache settings do I need to change to gain performance?
This blog doesn't talk about all scenarios, but will hopefully help you understand how each settings affect caching and assist you in making decisions. Please note that no matter what setting you have, you MUST always measure performance to prove that performance is better. Always begin with a baseline and then go from there.
I will also try and discuss the performance counter settings that you can use to measure caching in IIS 6.0 on Windows Server 2003 systems. So let's begin by understanding how HTTP Kernel mode caching works and then examining the settings that affect caching.
Caching of Static content For each GET request , the IIS worker process tells Http.sys whether or not to cache a response based on the "activity-period cache algorithm". If the same URL is requested twice within 10 seconds (the default value for the ActivityPeriod registry entry located at: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Inetinfo\Parameters) the IIS worker process tells Http.sys to cache the full response by URI. All subsequent requests for the cached response will be served from the cache.
Every 120 seconds, the Http.sys response cache runs a flush algorithm, which flushes the cached respponses that have not been requested within the 120-second interval. The flush algorithm is also called when IIS receives change notification for a file — that is, when the file has been edited or changed in some way. The HTTP response cache is known as the kernel URI cache in System Monitor. A web server administrator can configure the cache scanvenging period & the size of the responses that will be cached. Please refer to the Microsoft KB article below for the default values and limits.
Http.sys registry settings for IIS http://support.microsoft.com/kb/820129
Http.sys registry settings for IIS http://support.microsoft.com/kb/820129
CAUTION: Caching in kernel mode will increase performance, but also note that by doing so, you will be utilizing more kernel mode memory and therefore should be used with caution.
Scenario: If you have a static file called Default.htm on your site, you request it 2 times within 10 seconds, the response to default.htm will be cached in Kernel mode for the next 120 seconds. You can view this behavior using performance monitor logging. Let's first take quick look at the counters in question.
Go through Table D.13 Kernel Counters for the Web Service Cache Object on the Microsoft Website below:
So in the above scenario the performance counters should show the following values, assuming no other requests were made during this test:
Performance object: Web Service Cache
Did you notice the changes? The Kernel URI Cache Misses counter remains the same, however, the Kernel: URI Cache Hits in increased by one. So what this means is that for the first 2 requests in scenario 1, a lookup was performed in the kernel mode cache for default.htm and since it was not cached, Http.sys forwarded the request to the worker processes. It also recorded that the URI was not found in the cache by updating Kernel: URI Cache Misses. Worker process notices that both requests came within a time span of 10 seconds and it is for the same URI. It then instructs Http.sys to cache the response for the URI. There are however many times when the response is not cached in Kernel mode. Only responses that will be cached in the kernel are responses to HTTP GET requests.
The Microsoft KB article below lists the reasons why Http.sys will not cache responses.
Reasons content is not cached by HTTP.sys in kernel http://support.microsoft.com/kb/817445
Caching dynamic content in Kernel mode.
How to Cache ISAPI Responses in the Kernel To cache ISAPI responses in the kernel, you add the following cache headers to go out with the response:
• Cache-Control: public • Expires (Optional) • Last-Modified
It is recommended that the Expires value be calculated using an algorithm of current time on the server, plus the amount of time you want the cached copy to be served from the cache.
The information provided thus far is true for any static content. Caching behaves differently for dynamically generated content than for static content. KB: 817445 still apply. Things are handled differently when the request is for dynamic content such as ASP & ASP.net. ASP & ASP.net are handled by ISAPI extensions in IIS and has a separate processing pipeline. Also, these technologies allow developers to control caching programmatically. By default ASP & ASP.net content will be cached in Kernel if possible. You can enable or disable this feature by using the methods in this Microsoft KB:
An ASP.NET page is stored in the HTTP.sys kernel cache in IIS 6.0 when the ASP.NET page generates an HTTP header that contains a Set-Cookie response http://support.microsoft.com/kb/917072
David Wang (Microsoft) has a good post on Cache Insertion and Cache Eviction Policy, which I highly recommend reading. You can find it here:
According to this post, any dynamic page can be cached in the Kernel, IF the script engine that handled the request uses the ISAPI cache insertion policy mentioned in the post. I have't tested this with ASP much, but did try this with ASP.net. ASP.net exploits the Kernel mode cache extensively to provide better performance. By adding the following directive in an ASP.net web page, you can cache the response in a kernel mode cache
<%@ OutputCache Location="Any" Duration="120" VaryByParam="None" %>
NOTE: The other values of Client/Downstream/Server/ServerAndClient (Available in ASP.net 2.0) for Location tag didn't cache the response in Kernel.
The following cache related headers are added to the response by ASP.net. You can view this using a HTTP trace tool such as Fiddler or Web Development Helper.
• Cache-Control: public • Expires • Last-Modified
On the first request, you will see that URI Cache Misses counter is incremented by 1 and an HTTP Status code of 200. At the same time you will notice that the Kernel: Current URIs cached and Kernel Total URIs Cached will also be incremented by 1. It doesn't check if there was another request within a span of 10 seconds for the same URI to be cached. Note that over here, it is ASP.net ISAPI that specifies that the response must be cached. The perfmon counters will show the following values.
Web Service Cache
Configuring and Tuning Kernel mode caching
One of the first things you want to begin is by finding out what content to cache. You may want to identify pages that are frequently used. Rahul Soni (Technical Lead, Microsoft PSS - IIS/ASP.net & a close colleague of mine) has written an article on how to use log parser to get a graph of the most used pages on your web server. You can read it here:
Log Parser 2.2 and ASP.NET http://support.microsoft.com/kb/910447
Ensure is that Kernel mode caching is enabled in Windows Server 2003. If this setting is disabled, responses will never be cached in Http.sys. This setting is enabled by default and therefore it is not necessary to check this setting if you have a clean install of Windows 2003. You will want to check this setting if you upgraded from a previous version of Windows. All HTTP related parameters are located here in the system registry:
NOTE: All of the parameters discussed are DWORD values.
NOTE: Changes that are made to the registry will not take effect until you restart the HTTP service. Additionally, you have to restart IIS services as well. You can do this from command line as follows:
a. net stop http /y b. net start http /y c. IISReset /start