The obvious benefit. Serving up static HTML is an order
of magnitude (or more) faster than executing a bunch of ASP code. You are providing
a "snapshot" of the page to the user, rather than rendering it dynamically each time.
The caching is done per-URL... for example, let's pretend this is a page that lists all the company salespeople for
different states. The URLs to list the salespeople would look like this:
In each case the output
would be normally generated on the first request, then automatically be cached
for the next for 10 minutes. Remember, unique URLs mean unique HTML cache files.
Almost no code changes required
Only two minor additions to your ASP page
are required. A single include, and a single line of code:
Any ASP page can be completely and automatically retrofitted with page-level caching using the trivial code above.
It's completely backwards compatible!
Low overhead
This approach is extremely efficient. It requires very little
overhead. The only additional costs are per-page as described
below.
One application variable containing the date the page was last cached;
One HTML cache file stored on disk;
and an extra computation at page load. But it's an easy, fast one that looks something a bit like this:
if (date of app var for this page is older than cache minutes) then
(server.transfer to that HTML file, terminate execution)
else
(cache page to HTML file, set the app var date, and proceed normally)
end if
HTML Compression is now possible
Since static HTML pages are served, they are subject to
HTML compression, assuming you
have that option selected in IIS properties.
And you should! This is a giant performance win for bandwidth-- HTML
compression reduces absolute bytes transmitted by about a 5:1 ratio. So a 50k
page becomes a
10k page. That is a big big deal on a modem! And even on broadband it's
much snappier. Bottom line: bandwidth is expensive and precious, and client/server CPU time is cheap. Plus, the compressed documents are cached, so
the minor cost for compression is only paid once, not per retrieval.
I don't know if any of you have ever tried IIS
compression on ASP code, but it screws IE 5.x up royally. I had this enabled
under IIS (ASP and HTM compression) but I was forcde to disable
ASP part of the compression because the cached *.asp files were preventing
refresh of any kind, even with the F5 button. It was ugly. Real ugly. If
anyone has successfully enabled compression for ASP content, or
knows of a workaround to the problem I've described, please
e-mail me!
Anyway, another
advantage of this approach is that we
avoid the ASP compression
bug.
In case you're worried about the compatibility of compression, I
can assure you that all modern browsers, even text based ones, support the
HTML 1.1 standard, which includes compression.. it's all
quite standard and W3C approved
, and has been for years. A
couple very high traffic sites I frequent tested this and had no problems. After that I had no qualms in enabling it
for all my sites. It's damn near a no-brainer.
User-based trigger
One common approach to pre-rendering pages is to write
a script that runs in the background on a server, and dynamically builds the
page every 10 minutes. Our approach is an improvement on this,
because it renders the page on demand. So the first visitor to hit the URL
will trigger the cache HTM file build, then all subsequent hits to that URL
(for the next 10 minutes) will automatically and transparently be redirected to the HTML file.
If nobody is visiting the page, it doesn't eat up any CPU time!
Cons
Time based "freshness"
This is strictly a time-based caching method.. the cache "freshness" is determined by its age in minutes, and nothing
else. So if you have caching set for 60 minutes (1 hour), then update all your data, the page will stick around for an
hour regardless! You may prefer to have the page cache rebuilt when the data actually changes.. in which case you cannot
use this approach. Of course, you can always force the cache to be rebuilt manually or avoided altogether by passing in
the appropriate parameters with the URL.
It is possible to come up with a "smarter" page freshness trigger than "how long ago did I last render this page?"; however,
those smarter and more complex triggers will also require more work from the programmer!
Some pages must always be dynamic
Some pages can never be cached, because you absolutely must make sure the user is always seeing the
most up to date information possible!
Page Caching may not be the best approach
The benefits of page-level caching will depend on several factors.
How long does your ASP page take to execute? (longer is better, short is worse)
How many "hits" per day do you expect for the page? (more hits is better, less hits is worse)
How "fresh" does the page need to be for your users?
(not very fresh is better, always fresh is worse)
The answer to these questions will determine whether
page caching is useful to you or not. If you have lots of complex ASP pages,
tons of page hits, and not a pressing need for up to the second data, that is
a good candidate for page caching. Conversely, if you have simple ASP pages,
few hits, and must show real-time data to every user, that is a bad candidate
for page caching. Most pages will be somewhere in-between these two extremes!
There are other kinds of Caching
Page-level caching
is a form of output caching. It may be more desirable to cache
the inputs for the page: the database. There are various methods of caching sql results
or even entire tables, but that's outside the scope of this article.
A Real World Example
Let's say you ran a gaming news page like Blue's News.
This web page is updated with fresh gaming news about 10 times per day on average.
It also has a tremendous traffic level. With a traditional ASP approach, the news page
would be generated from the news database every time a user visits the page.
For a heavily trafficed web site like this one, automatic time-based caching makes perfect sense.
Even setting the interval as low as 10 minutes could be a big performance win.
Let's say you have 30 requests per minute-- about one every two seconds. Without caching, that would
result in 300 page renders in that 10 minute period! With caching, you only render the page
once, and the next 299 requests will be served up fast, compressible static HTML. And you can add
that caching ability automatically, with two lines of code, without changing any of your existing code!
The only downside, of course, is that users may see a 10 minute old version of the page. But considering
the sporadic nature of the updates, this is a very small tradeoff. It's unlikely that visitors would
be upset by seeing 10 minute old news!
As you can see from this example, caching can improve performance dramatically! And this include makes
it easy!
This code has been substantially rewritten and improved, but it is based on work originally done
by John Peterson in this article!
Thanks John, for coming up with such a cool and clever technique!
Any questions or comments on this code can be directed to me at wumpus@gamebasement.com.
Happy coding!
Getting The Code
The code mentioned above can be downloaded from here.