Sunday, September 28th, 2008...11:36 pm
Caching Part 5: View Caching
By: Robert Baskin (Online Director)
Jump to CommentsWell, after some delay, I can now bring you the final post in my caching series. This one is about view caching, which is where the real awesome technology happens! If you haven’t read parts one, two, three and four, go back and take a look at them first – this post will make more sense that way.
So to summarize, we’d developed a caching system and switched to memory-based caching. Our site was doing fairly well – rebooting the server on a semi-regular basis was a distant memory. But in early April 2008, we hosted the first ever Yale Daily News Web Conference, where we invited students from other Ivy League newspapers involved in their online operations to come and talk about putting a college newspaper online. It was a good time; maybe I’ll blog about it in the future.
At that conference, I hosted Thomas Bukowski from The Dartmouth for the night. He showed me some of what he had been doing for their site, including how he handled view caching. His work, which made his site serve very quickly on less powerful hardware than us, inspired us to implement view caching on our site. Now let me explain exactly what view caching is and why it’s sweet.
We were caching the data we retrieved from MySQL, which was the most expensive operation and saved us quite a bit of processing and immensely helped our server load. However, after we retrieved the data from the cache, we still had to generate the HTML we send to the user, including all of the conditional statements, loops and other code that take some time and energy. Instead, why not save the page that is generated and serve that, instead of going through all of the presentation code every single time? The idea is that as soon as possible in your code, you check and see if you have a cache available. If you do, serve the cache and stop processing. If you don’t, process the page and save the cache when you’re done. That way you don’t have to do it next time.
Sounds good in theory, but it takes a little bit of work. We started by putting our code in /path/to/app/config/bootstrap.php, which is the earliest place CakePHP is booted up and allows you to execute code. The first problem we ran into was that we allow users to register accounts and log in. If you do that, you can see a personalized welcome message in the top right instead of “Log In – Register.” If we cached the page with “Welcome Joe,” that wouldn’t be good for everybody else. The solution was to check and see if a session exists for the visitor – if so, we don’t serve a cached page. Fortunately, most people don’t log and set a session, so for everybody else we serve a cached page.
We also don’t want to serve a cached page if there’s form data being POSTed or GETed. So we check and make sure those two superglobal arrays are empty. If they are, we begin our caching logic. We check and see if the cache is set for this page. If so, we get the cache and print it out, and the page is served. We also print how long our code has been executing for up to that point in a comment below the HTML. If you’re not logged in, check out the bottom of the source. You’ll see something like “<!– cache took 0.0009s –>”. Not bad.
If the cache isn’t set, we start output buffering with ob_start(). Then, as the last code that executes after every page, we check if we’re buffering with the line “if ( ob_get_level() >= 1 )”. If so, we store the content into the cache. The next page that’s requested is served from our lightning-fast view cache. With view caching enabled, we were able to survive our perfect storm.
How could we make this even better? Well, nginx has the ability to access memcached directly. It could directly check if a view cache existed, and if so, serve it. Apache would never start and it would be unbelievably fast. That would involve switching from XCache to memcached, which is something we haven’t done thus far, but may do in the future.
That concludes my series on caching. Fin.
Leave a Reply
You must be logged in to post a comment.