Continuing my path along optimization posts, I thought I would write about a trick that I use to optimize website performance and help scalability by reducing resource consumption.
I recently read a post about continuous cache warming techniques for Rails. Even though the author specifically states you shouldn’t use the techniques in production, I know that there are developers who do. Sometimes we do crazy things for performance reasons. Cache warming is priming the cache; artificially hitting a resource to put it in cache or reset it’s expiration. But this is unnecessary and It defeats the purpose of cache expiration and can unnecessarily consume memory.
Before we start…
I really want to stress that while I’m discussing a specific technique, I want you to think about the concept behind it as it can be applied to other areas in different ways, not just web pages.
The problem is content, or at least the generation of content. Web pages can contain many different areas that are dynamically assembled when the page is requested. Often times when I’m evaluating a poorly performing web site I see areas of content that are generated far too often (sometimes on each request) while using resources like calls to a database to accomplish the task. I always have to ask the question, how often does the data change and how fresh does it actually have to be?
Examples of these types of areas are
- Latest comments
- Poll results
- Trending topics
Let’s evaluate the Inland Empire .NET Users Group website home page as an example.
We’ll focus on only two areas of this page. The first area (red box) is the main content. This describes the next event and gives speaker details and other information. The second area (green box) shows a leaderboard for the Most Valuable Member program (yes, I’m currently leading at the time of this post).
Both areas get their data from a data store. On each page load both areas must make at least one request to query the data store and get the information to be displayed. So each page request will make multiple calls to the data store? Probably not. Mechanisms like page caching will prevent this by serving the previously rendered output of a page (or widget) from memory for each subsequent request thus by-passing any need to render the content again.
But what does this really mean? It could mean different things to different sites. With page caching, the rendered output will go into memory which is a limited resource. It also means that the request must still go through the ASP.NET pipeline. At some point the cache will be cleared. Either by expiration, need for more memory or from the app pool recycling. This means the page will need to be rendered again on the next request. For a page that changes very frequently this might be the desired process. Our example site changes once or twice a month so it isn’t optimal.
A technique I use involves the file system. Yep, I generate actual .html files. Let’s take the leader board area of the example page. It’s nothing more than an unordered list in the end. It changes once a month. Why would I want to make calls to the database more than once a month when the results will be 100% the same? Why would I want to store a snippet of simple HTML in my limited memory when that content isn’t being requested? Why would I want a request for the leaderboard HTML to go through the ASP.NET pipeline? I don’t want to do any of those things for a piece of content that will more than likely be the same as the last time it was requested.
Caching the leaderboard HTML to an actual .html file accomplishes a few things. First, it saves the rendered html for later use so there is no need to rebuild it (i.e., no unnecessary calls to the data store). Second, it stores the rendered content outside of the memory. We’re safe from cache expiration and app pool recycles. Third, the content becomes a static resource which means it will be served by IIS using the StaticResource handler, which is blazingly fast, instead of going through the ASP.NET pipeline. Your setup may vary.
When to build content
The majority of the time I use schedules tasks to regenerate the content at set schedules based on the content and how fresh it has to be. Other times I will need a trigger to kick off the process. For triggers I tend to use message queues. The goal is to move the work outside of the web application, especially if the generation of content takes abnormal amounts of time.
I’m purposely being generic by not going into how to implement the technique because there are numerous ways and it depends on you, your team and you’re project. I’ve used server side includes and JQuery requests for calling content (and async loading) and T4 to generate content. I like to use scheduled tasks or cron jobs (when possible) to kick off scheduled builds and message queues like MSMQ for triggering a build.
Is it right for me?
Maybe. There are some things to consider first. Is the time to implement this technique worth the result? Bandwidth can be another concern. Depending on how the static HTML is requested (e.g., JQuery GET), you may run into bandwidth issues if the browser isn’t serving the request from cache. Another issue is content that changes based on parameters. You may not have access to the server to setup a scheduled job or a message based trigger system. Disk space can also become an issue.
Let me know your thoughts.