HOWTO: Use the HTTP.SYS Kernel Mode Response Cache with IIS 6
Motivation
One of the bigger buzz-word features of IIS 6.0 on Windows Server 2003 is the "HTTP.SYS Kernel Mode Response Cache".
When you do a search against "HTTP.SYS Kernel Response Cache IIS 6", you will inevitably find a large body of literature repeatedly talking about how the kernel mode response cache effectively improves performance and lightens server load by removing the kernel/user mode transitions, improves request/response latency, improves... blah blah blah blah blah... and is the best thing since sliced bread.
Unfortunately, there is not a lot of concentrated, pragmatic information which focuses on the internals of how this cache works so that one can effectively take advantage of this feature. Specially, from within the context of IIS 6.0 and ASP.NET by association since it is an ISAPI Extension DLL.
This lack of consolidated information, along with several newsgroup questions about how the kernel mode response cache works, is what motivated me to write this entry about the background and the raw mechanics of how to leverage this cache from IIS 6.0.
Cache Basics
The best way to understand a cache is by understanding how to:
- Place an item into the cache (cache insertion policy).
- Remove an item from the cache (cache eviction policy).
Now, how does this translate to IIS 6.0 using HTTP.SYS?
Cache Insertion Policy
There are two ways for IIS 6.0 to insert an item into the HTTP.SYS kernel mode response cache:
- The IIS Static File Handler. If you make two requests for the same resource handled by the static file handler within a 10 second contigous interval (configurable via the ActivityPeriod registry key), the resource will be placed into the kernel mode response cache.
- ISAPI Extension calls HSE_REQ_VECTOR_SEND to send a complete HTTP response which includes at least the HSE_IO_SEND_HEADERS, HSE_IO_FINAL_SEND, and HSE_IO_CACHE_RESPONSE flags, along with a Last-Modified: and optionally an Expires: response header.
You must realize that just applying the cache insertion policy does NOT ensure that HTTP.SYS actually caches the response. There are many other variables that affect the cacheability of the response, as documented at this URL.
Of course, there are also limits on what can be placed into the kernel response cache. The most interesting variables from an ISAPI perspective are:
- Response Size - 256KB by default and controlled by the registry key HKLM\SYSTEM\CurrentControlSet\Services\HTTP\Parameters\UriMaxUriBytes
- Scavenger - 120 seconds by default and controlled by the registry key HKLM\SYSTEM\CurrentControlSet\Services\HTTP\Parameters\UriScavengerPeriod
For more info on other registry key tweaks, see:
Personally, I would not tweak with the registry keys unless you know you need to.
Cache Eviction Policy
The HTTP.SYS kernel response cache, as exposed by IIS, has a very simple cache entry eviction policy - whichever of the following criteria triggers first will flush the associated cache entry(s):
TTL (Time-To-Live) - Set by the Expires: header in the response.
HTTP.SYS Scavenger - UriScavengerPeriod controls the frequency with which the scavenger will evict any cache entry that has not been accessed in the last UriScavengerPeriod amount of time, in seconds.
On-Demand - ISAPI Extension can use the HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK ServerSupportFunction to retrieve a pointer to the on-demand URL revocation function, and you call this function pointer with the FULL URL (obtained via the UNICODE_CACHE_URL ServerVariable when you cached that URL's response to begin with) to evict that URL's cached response.
For example, suppose your ISAPI decides to use HSE_REQ_VECTOR_SEND to cache a certain response. If you want to be able to evict it later, using your own cache policy, you want to retrieve and keep the UNICODE_CACHE_URL ServerVariable when you make your HSE_REQ_VECTOR_SEND call. Then, when you want to evict that entry for whatever reason, you call call the cache invalidation callback using that saved UNICODE_CACHE_URL value.
Now, a subtle point with the timing-related eviction policies. HTTP.SYS does NOT immediately evict cache entries when their time is up. Instead, it sweeps through the response cache with a 30 second granularity. What this means is that suppose UriScavengerPeriod is set to 60 seconds. Cache items can between 60 and 89 seconds old, depending on when the cache item was inserted relative to the last periodic sweep.
However, On-Demand invocation is immediate - as soon as you call it, you will get a cache-miss if it used to be a cache-hit.
Conclusion
I hope that my explanation helps clear up the roadmap of how to use this exciting HTTP.SYS feature. If there are any unclear points, feel free to post comments for the benefits of everyone. I will try and follow up with all comments to make this information useful.
Some final observations:
- A static file (i.e. .htm, .css, .js, .jpg) is NOT guaranteed to be kernel response cached. You could have an [Wildcard] Application Mapping that applies to those extensions, in which case it depends on the cache insertion policy applied by that Application Mapping (as well as the other cacheability factors that I described earlier) when it handled the request and generated a response.
- A dynamic page can be kernel response cached IF the script engine that handled the request uses the ISAPI cache insertion policy mentioned above.
//David
Comments
Anonymous
July 14, 2005
The comment has been removedAnonymous
July 15, 2005
The comment has been removedAnonymous
July 15, 2005
The comment has been removedAnonymous
August 11, 2005
David,
Would it be possible to post some sample code on how to get a URL into the Cache from an ISAPI extension? The docs for HSE_REQ_VECTOR_SEND are sketchy at best and I'm not clear how set up the call and what to pass. Do you still use WriteClient or pass all to ServerSupportFunction or what?Anonymous
August 11, 2005
Yes, I'm planning on posting in another entry source code on how to both insert and invalidate the HTTP.SYS cache from ISAPI using HSE_REQ_VECTOR_SEND. I am just a bit swamped with IIS7 work at the moment (see my recent blog entries).
What aspect of the HSE_REQ_VECTOR_SEND documentation do you think is sketchy?
The earlier versions (which I never knew about nor reviewed) were pretty bad, but the latest version from Feb 2005 should have everything necessary. All the flags are finally there and described, related SSF function calls and structures are linked correctly, and everything is documented. Only thing thing that could be missing is a code sample, but that is not platform documentation.
A "HOWTO" document belongs elsewhere and was an article I planned to write (in the past) and publish through the MSDN/KB system, but I don't need to do that anymore because I'm just going to write it up and blog it now.
//DavidAnonymous
October 12, 2005
I think the IIS kernel caching is what is causing my RSS feed (index.xml) to be cached with old information. I have to restart IIS for the latest RSS feed to diaplay or wait what seems like an eternity for the latest RSS feed to display.
Is there a way of excluding certain files from kermel caching or at least force it to re-cache the file if the file changes?
ThanksAnonymous
October 12, 2005
Tom - Why do you think that kernel caching is the issue? Is the kernel cache hit perf counter increasing?
I presume .xml is handled as a static file on your server. If it is not, then this cannot be an IIS issue since caching behavior depends on the handler.
By default, IIS static file handler uses file-change notification to detect file changes and flush the appropriate cache(s).
There is no built-in declarative mechanism to include nor exclude resources from kernel caching, though it would not be very hard to implement the exclusion logic - just use a IIsWebFile to make a configuration setting on index.xml such that it fails the aforementioned caching criteria.
//DavidAnonymous
October 13, 2005
>> Why do you think that kernel caching is the issue?
If I open the file locally on the IIS server, the file is current. If I go to another PC which has never loaded the index.xml feed (not cached by the browser), it often loads an older version of the file. The only way I can see that happening is if the kernel is holding the file in memory.
I can even DELETE the index.xml file fom the IIS server and IIS will continue to "serve" the file as though it still exists. Weird, eh?
If I then stop/start IIS then I'd get a file not found error on my browser. (or if I didn't delete the file, restarting IIS makes sure the most recent XML file is served)
I assumed since the kernel cache caches heavily accessed files, such as my blog's RSS feed, that the kernel was keeping the file in memory and thus serving it from the kernel instead of the hard disk.
>>Is the kernel cache hit perf counter increasing?
Not sure how to add this to the performance monitor. I'll have to look into this.
>>I presume .xml is handled as a static file on your server
Not exactly sure what you mean. It isn't defined as a MIME type in the IIS Manager. Should it be? I didn't think I had to define the "common" file types under HTTP Headers, MIME Types. I'll ask our main IIS web guru about that.
Thanks for your help.Anonymous
October 14, 2005
The comment has been removedAnonymous
November 03, 2005
Due to an encountered problem with caching it was decided to turn off caching within the registry. Whilst the implemntation uses IIS6 it is running in IIS5 compatability mode. The cache was proven to be Server side with the problem being when the client browser was closed and the same URL hit from another browser on any other netwoked machine cached information was displayed. Is anybody ware of a similar issue.Anonymous
November 03, 2005
Stu - Well, if you say that you rule out client-side cache by using different clients, and you rule out server-side cache by turning it off, then you probably need to look at caches in between the client and server in the network layer, like Proxy Servers and the like.
Now, you did not state WHAT type of content was cached - static or dynamic content (as identified by IIS) - because static content cache is controllable via metabase and/or registry key settings, but dynamic content cache is completely arbitrary and depends on the ISAPI implementation (this blog entry should have made that clear).
//DavidAnonymous
November 10, 2005
David- Thanks for your reply this issue was concerning dynamic content and investigation is ongoing around the ISAPI implementation. It is noted that this issue is not encountered with IIS5. The theory is that the third party security runtime ISAPI is not coded correctly for IIS6.Anonymous
November 23, 2005
David I am having the exact same problem Tom described. I have an XML file that when updated on the hard drive is not updated via http. I have disabled all asp.net & asp processing. I have enabled immediate content expiration. I have removed the "application" making just a straight static web server. It still caches. The XML file is updated on the hard drive every 5 minutes or so. In order for it to update via HTTP I have to do an IISRESET. Any help would be appreciated. FYI, this was a fresh Win 2003 install w/ all updates applied.Anonymous
November 23, 2005
Please see:
http://www.experts-exchange.com/Web/Web_Servers/IIS/Q_21037463.html?query=IIS6+Cache&clearTAFilter=trueAnonymous
January 17, 2006
Recently,I write a iis filter for iis 6.0;
but,i found that event client cancel download
file,but filter can receive "sf_notifiy_send_raw_data" up to 2000 times.
please help me! email:fujiachun@163.com
Thanks!!!!Anonymous
January 17, 2006
fublogs - The behavior is by-design on IIS6 due to HTTP.SYS buffering of the outgoing response. There is no way for an ISAPI Filter to detect if the client cancelled the download or not. There is full discussion of this on the newsgroup microsoft.public.platformsdk.internet.server.isapi-dev :
http://groups.google.com/group/microsoft.public.platformsdk.internet.server.isapi-dev/browse_thread/thread/73cde21658c5be27/118e4c7d608a311e
http://groups.google.com/group/microsoft.public.platformsdk.internet.server.isapi-dev/browse_thread/thread/c9ebb5f37d8f7d61/8c2b6dbca5231633
//DavidAnonymous
February 12, 2006
I was wondering about the use of NPP by HTTP.sys doing HTTP response caching. I guess I might be making a wrong assumption, but I thought...
(1) HTTP.SYS is a kernel mode driver.
(2) Kernel mode drivers can only access NPP.
(3) NPP is restricted to 128Mb RAM on X86 architecture.
If that's right, then 128Mb doesn't seem a lot of space for caching, especially since you wouldn't want to use all of the NPP!
Thanks if you get a chance to address this in your blogAnonymous
February 13, 2006
Luke - yes, you are making some wrong assumptions... :-)
Kernel mode code can access much more than just NPP.
HTTP.SYS actually uses available physical memory (configurable limit) for the cached response content of the "kernel response cache".
//DavidAnonymous
February 21, 2006
David, would POSTs with 200 0 64 reponses (from IIS log) be cached. What I'm experiencing is these responses are being repeated until a 200 0 0 response is returned. This causes multiple posts within seconds of each other.
I have not been able to find a concrete answer to tell me what the 200 0 64 or 200 0 1236 mean.
I hope you can help shed some light.Anonymous
February 21, 2006
The comment has been removedAnonymous
February 23, 2006
Thanks for the quick response David. After another day of troubleshooting duplicate posts, I have no solid answers. The users swear they only pressed the Submit button once. We're seeing GET and POST requests with the 200 0 64 responses. While I don't care much about the GETs, the POSTs are killers as it will cause the app to post multiple times, creating charging or crediting clients multiple times.
It’s happening at random on two load balanced servers, each with quad CPUs. The app was just migrated from W2K to these W2K3 servers. We did not see this issue in Stage where UAT and Intergration Testing was done.
Is there a way to configure IIS to prevent identical POSTs that have 200 0 64’s in the last 10 seconds or to treat all 200 0 64s as a 500 errors?Anonymous
February 23, 2006
Charm - The safest and easiest way to prevent multiple POSTs is for your application to synchronize the action itself. People tend to use Session State to do this... and if you load-balance and use out-of-process Session State, users can bounce between the load balanced servers and still not duplicate POST.
In general, this sort of problem is best solved at the user application level. The notion of "preventing identical posts within the last 10 seconds" does not solve the underlying logic problem at the application layer.
//DavidAnonymous
May 15, 2006
"A static file (i.e. .htm, .css, .js, .jpg) is NOT guaranteed to be kernel response cached. You could have an [Wildcard] Application Mapping that applies to those extensions"
Hi,
A newbie question: I need kernel caching for .jpg files. To what application should I map?
Thanks...Anonymous
October 03, 2006
David, Just a quick question: If you use HttpContext.RewritePath in ASP.NET does that mean you can never benefit of kernel mode caching? A yes/no answer would suffice. A more detailed answer would be greatly appreciated. Thanks, AdiAnonymous
October 05, 2007
Hi David, In your February 23, 2006 reply - you have mentioned "The safest and easiest way to prevent multiple POSTs is for your application to synchronize the action itself." I would request you to share the technic/logic to be used to identify the duplicate POST request. Thanks, DharmeshAnonymous
January 01, 2008
I am not able to access a sql end point (created on a live server) from a proxy server enabled LAN. I am using Windows Server 2003 SP-1, So do I need any registry edit?Anonymous
January 05, 2008
Rob - .jpg files are kernel response cached by default unless otherwise configured. Read the URL link in this same blog entry for the full meaning of "otherwise configured". //DavidAnonymous
January 05, 2008
Adi - rewriting the URL breaks all caching, kernel response included, by definition. IIS cannot be certain that your custom code rewrites URLs consistently to ensure cached responses are also consistent and correct. Thus, if any code attempts to rewrite the URL, caching is disabled. //DavidAnonymous
January 05, 2008
Dharmesh Shah - thanks for the request, but I believe it is an exercise to be completed by the reader. Please read my BIO on why I do not answer questions posed like your own. If you have a specific question on how to do something, then I will try to help with knowledge -- but I cannot just "do something for you". //DavidAnonymous
February 05, 2008
Hello, Your post helped us find our problem well. I've verified that the pages are being inserted into the HTTP.SYS Response cache, but the problem is it doesn't update. We are a hosting company, and our clients CSS files do not update during design modifications. Recycling the application pools does not help, I believe restarting IIS doesn't help either (neither of which are acceptable). I need a way to force the HTTP.SYS to run its algorithm to get new content static pages. "On-Demand - ISAPI Extension can use the HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK ServerSupportFunction to retrieve a pointer to the on-demand URL revocation function" Well.. This page is specific to Microsoft Visual Studio 2008/.NET Framework 3.5 I am running classic ASP and do not have the option to run .NET to do this. Am I just up the creek on this one?Anonymous
February 05, 2008
Hi David, I have a problem same as brad posted above. Is There any way to use this future with classic ASP? Can'I solve the problem by write ISAIP Filter or other programs ?Anonymous
April 25, 2008
The comment has been removedAnonymous
November 05, 2008
David, I need to flush periodically the entire IIS6/7 http.sys cache programmatically from a filter dll. The cache invalidation function obtained via HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK apparently works on a single URL -- or is there a wildcard to zap all? One other bit of advice I see is to set cache invalidation time to zero, then back to the original value, presumably via CacheControlMaxAge, or some such. But does this work without restarting the service? Many thanks for your informative public-spirited site. --MikeAnonymous
January 08, 2009
Is there any way to monitor cache flush events? I want to see why the Current Files Cached and Current URIs cached continually get flushed. There is no expires: in the headers, the TTL is set higher and the scavenger period is set longer than the frequency with which these things seem to get flushed. (IIS 6.0) SteveAnonymous
January 12, 2009
Is there any way to configure IIS to clear cache at the end of every session? What are pros and cons?Anonymous
January 13, 2009
Abhijeet - Can you clarify what you are trying to accomplish? There is no such thing as "session" in HTTP or IIS, so your question has no direct meaning. //DavidAnonymous
May 12, 2009
Win2K3 + II6 Double Posts: Trying to uncover the reason why IIS6 would not be logging requests for 2 minutes. An outage reported by an external ping, first thought: connection issue. However a little more digging and the IIS time is specified as the end time by http://www.w3.org/TR/WD-logfile.html (microsoft refers to it as the time the activity occured) so naturaly start time should be calculated by subtracting the time-taken from end time. Now to prove this I've made a very simple asp script. it sleeps for 10s using the SQL Server. I ran the script these are my results: please note connection error the first time it ran then an automatic re-request which took 17 seconds for a script that is supposed to take 10 seconds. this produces more questions then answers I was not able to reproduce this behavior again (however maybe some of the issues we're having could be explained by this misterious behavior), I've tried renaming the script changing the code a bit, but it now always produces a single entry of little more then 10s.
Script Output: First Run: Start time: 15:38:03 End time: 15:38:13 Second Run: Start time: 15:53:45 End time: 15:53:55
IIS logfile: 2009-05-12 20:38:03 W3SVC920801317 GET /inc/sleep.asp - 80 - 76.65.237.13 HTTP/1.1 Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+en-US)+AppleWebKit/525.19+(KHTML,+like+Gecko)+Chrome/1.0.154.65+Safari/525.19 ASPSESSIONIDAABBRBAB=MIKCIGIAODFAAMDIGHMMJGAE 200 0 64 220 508 10171 2009-05-12 20:38:13 W3SVC920801317 GET /inc/sleep.asp - 80 - 76.65.237.13 HTTP/1.1 Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+en-US)+AppleWebKit/525.19+(KHTML,+like+Gecko)+Chrome/1.0.154.65+Safari/525.19 ASPSESSIONIDAABBRBAB=MIKCIGIAODFAAMDIGHMMJGAE 200 0 0 260 508 16749 2009-05-12 20:53:55 W3SVC920801317 GET /inc/sleep.asp - 80 - 76.65.237.13 HTTP/1.1 Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+en-US)+AppleWebKit/525.19+(KHTML,+like+Gecko)+Chrome/1.0.154.65+Safari/525.19 ASPSESSIONIDAABBRBAB=MIKCIGIAODFAAMDIGHMMJGAE 200 0 0 260 508 10062
Anonymous
June 05, 2009
One more question. Does IIS6 and IIS7 have any simple way of reloading file caches? At the moment I'm mostly concerned with the cache for the compiled classic ASP files. I'm using NTFS junctions for versioning and instant reverts. However IIS does not detect that the files have changed. The only way that I found how to get IIS6 to reload the files without loosing sessions, is to change the following metabase properties to 0 AspScriptFileCacheSize="0" AspMaxDiskTemplateCacheFiles="0" AspScriptEngineCacheMax="0" and then change them back. Surely there must be some simple scriptable interface for controlling various caches in IIS?Anonymous
August 07, 2009
Hi David, I have been looking for the answer to this for a few days, but haven't been able to get it answer. I have three environments setup identically (DEV, QA, STAGING) using IIS. We have recently made changes to an RSS generator app where we only added a new parameter in the querystring. We found that in DEV and QA environment RSS is not being cached. But when we moved application to our STAGING environment, response is being cached for the <ttl> period of time specified in the RSS. Any ideas as to how the cachin and ttl works in this situation? Where is it stored? Any lights to this issue would be really appreciated. Thanks Daniel MizrahiAnonymous
January 20, 2011
Question FOR IIS 7 I've following in web.config <caching enabled="true" enableKernelCache="true"> <profiles> <add extension=".cab" policy="DisableCache" kernelCachePolicy="DontCache" /> </profiles> </caching> As above, DontCache doesn’t prevent other modules from setting kernel cache policy. For static files, static file handler sets kernel cache policy which enable kernel caching of the response. In server DisableCache option makes sure that response doesn't get cached in kernel. SO I have *.cab in kernel mode cache [verified by netsh show cache command] Will my Cache Response is going to be Flushed when the actual content is changed[FCN] when I have set kernelCachePolicy="DontCache" instead of kernelCachePolicy= "CacheUntilChange" ? Thanks JAsAnonymous
January 20, 2011
Question FOR IIS 7 kernel mode Caching I've following in web.config <caching enabled="true" enableKernelCache="true"> <profiles> <add extension=".cab" policy="DisableCache" kernelCachePolicy="DontCache" /> </profiles> </caching> As above, DontCache doesn’t prevent other modules from setting kernel cache policy. For static files, static file handler sets kernel cache policy which enable kernel caching of the response. In server DisableCache option makes sure that response doesn't get cached in kernel. SO I have *.cab in kernel mode cache [verified by netsh show cache command] Will my Cache Response is going to be Flushed when the actual content is changed[FCN] when I have set kernelCachePolicy="DontCache" instead of kernelCachePolicy= "CacheUntilChange" ? Thanks JAs