Friday, March 1, 2013

Web Optimzation: Cache Maximization versus Request Minimization


A couple years back when I started getting interested in Single Page Application [buzzword detected] techniques I was looking at using templates and sending JSON data in order to separate fixed markup from volatile data. In the context of what I was working on this reduced the amount of data going over the wire. There was a lot of repeated markup and using a single template bound to JSON meant the markup was sent once as opposed to once per data object in the JSON.

One thing I wanted to do, but didn't have time for, was to take the next step. To store those templates in local storage and cache them so subsequent requests wouldn't have to refetch the templates. So I have started to look a little at Silo and I felt like I would blog some of my thoughts about web performance.

How do you improve web performance? Big question, but there are two main answers. One, make fewer requests. Two, cache stuff. The fewer request answer includes things like combining your images (CSS Sprites) and bundling your JavaScript and CSS. Cache stuff includes thing like moving your JavaScript and CSS into js and css files and setting up your cache headers correctly. Pretty basic advice you will find if you look at Yahoo's (Yslow) and Google's (PageSpeed) recommendations.

So maybe you detect a fundamental problem? You should make fewer requests by combining everything together. But you should also make lots of fine grained requests to maximize what you can cache. Doh! The essential issue is that caching is based on requests. So you have fighting goals of maximizing cacheability and minimizing requests. Hey, how about we control the caching ourselves?!?!? HTML5 web storage is supported in almost every browser, and if you are dedicated to supporting IE6 and IE7 (browsers that Microsoft has told people not to use) there is a funky data storage thing you could potentially use. Personally I am of the camp that you shouldn't try to support every browser. But that is a vitriolic rant for another day…

James Micken (Google "Funniest man at Microsoft Research") has been doing research around this and has come up with a Silo system. So his idea is that you combine everything on your page into one big file and you do a single request. You then have an automated tool divide this giant page into chunks and you store your chunks. You send chunk ids in a cookie when you request the page and the server creates a new page, but then only sends back the chunks that are needed. So this is very cool and James is a goofy presenter so his presentations are worth watching, but I have a couple issues with this.

One is that going down to a single request may not be that great. Browsers tend to use four request threads and I have seen some evidence that multiple downloading threads increase the efficiency of your download. The other is that the biggest advantage of caching certain requests is that they can be reused on other pages. I am mainly thinking about JavaScript and CSS, but like I mentioned at the beginning templates could also be stored. Most sites I have worked on have JavaScript and CSS files that are used on multiple pages. Combining them into a snigle page via Silo means they are going to be sent more than is necessary.

So Silo is cool because you don't really have to worry about the caching. You just build a page with everything on it and then an automated system will take care of the caching mechanism, but I think you can get better results if you ask the web developer to do some thinking and divide their project. You can also get a lot of improvements if you view a webpage as a SPA and separate fixed markup from volatile content. Silo has a system which caches non-volatile chunks, but it has no real notion of which chunks are volatile. Also Silo ignores savings between pages. For example, most web site have a header that appears on every page.  This basically static header is often sent over and over and this really is a waste.

So imagine dividing your page up into 4 categories: JavaScript, CSS, Templates of Markup, Volatile Data as JSON. So you can see that three of those things do not change much and three of them may be used by multiple pages.

You can also use interesting techniques of loading the pieces of the next page while you are on the first page. Or if you are using a pure SPA approach you can delay loading pieces of the page that may not initially appear. Okay I will walk through the basic pattern.

Client: Request with Empty Cookie
Server: Page returns with JavaScript shim and a series of Templates, JavaScript sections, Style sections. Each section has and associated ID
Client: JavaScript shim constructs page from sections and stores sections in web storage and tells cookie what sections it has stored. After the page is built the client starts loading sections for other pages and stores them in web storage and their ids in the cookie.
Server: Responds to these behind the scenes request with sections.
Client: User decides to navigate to a new page and sends a request with a cookie full of Ids.
Server: Server again passes back a JavaScript shim and a series of sections whose ids are not present in the cookie

Now, it is fairly trivial to attach version identifiers the the ids in question to handle updates in your code.

I think techniques like this will become more and more common and I will work more on the nuts and bolts later.

No comments:

Post a Comment