Web developers keep devising more and more clever hacks that help work around HTTP level issues like overhead from roundtrips and lack of parallelism. The problem is that a lot of these techniques are not magic bullets, but have some important tradeoffs. Here I go through two such hacks and how they are suboptimal and hopefully will be unnecessary if a prioritized multiplexing protocol that looks like SPDY gets standardized as HTTP/2.0. With prioritized multiplexing, the natural way of authoring content will hopefully also be the faster way, and then these hacks can hopefully fade away into irrelevance. This isn’t an exhaustive list of hacks and why they suck. They’re simply two that I have run into as of late that I haven’t seen discussed elsewhere (but could be wrong).
CSS Sprites are pretty neat, because they help reduce roundtrips by combining multiple image into a single image, thereby reducing the number of image requests (at some cost). CloudFlare does an awesome job spriting their website. For example, their CDN features page utilizes CSS sprites to great effect, helping reduce the number of requests. But it’s useful to examine the waterfall to see how referencing images in the stylesheet instead of the main document can slow things down.
As you can see, referencing the images in an external stylesheet requires downloading the stylesheet before the image gets requested. One might reasonably ask why we don’t speculatively download image resources in the stylesheet as the stylesheet comes in, but many stylesheets include a bunch of resources that are never used. For example, here’s the stylesheet included on my Google search for [flowers] when I’m signed in. Chrome tells me there are 96 instances of “background:url(” in that stylesheet, and you can bet that we’re not using all those resources on the Google search page. Note that waiting for the external stylesheet download to complete to issue image requests happens anyways in Chrome stable and IE.
So we have the situation where, in order to reduce the number of image requests, many content authors switch from using normal tags to using CSS sprites. This prevents the browser from discovering the resources during speculative parsing (e.g. WebKit’s PreloadScanner) and instead we have to wait for the stylesheet to complete downloading and then for the rendering engine to match the CSS selector for the parsed element to decide to request the appropriate background image. It’s particularly frustrating because CSS sprites are a commonly accepted “best practice” by web developers, because they do indeed help workaround deficiencies in HTTP, but it also prevents the browser from loading resources as early as possible.
Note that CloudFlare’s making the right tradeoffs here in an HTTP world. But they could be even faster if they undid that optimization and just declared the image resources normally in the document when serving over a prioritized multiplexing protocol like SPDY (and hopefully HTTP/2.0 in the future!). CloudFlare’s been pretty quick about iterating on new technologies, so I have no doubt that they’ll pick up on this missed optimization.
Hostname sharding is another commonly accepted “best practice” designed to work around HTTP’s lack of parallelism. It’s true that it does indeed make browsing faster in general, but it has numerous downsides. It increases the number of connections, thereby increasing resource consumption at TCP endpoints and middleboxes, increases DNS traffic and entries (and the TCP connection is blocked on the DNS lookup), and splits congestion control information across multiple connections. Moreover, more parallelism doesn’t necessarily make things faster. It might result in more contention and more interleaving. For more details, see Patrick’s post on the matter.
The benefits have been written about numerous times already, so I won’t bother repeating them. But I will warn about the dangers of hostname sharding, in particular because Patrick McManus showed me that it was being abused. Some sites seem to be using a scary number of shards, and it’s pretty bad for the internet and for their performance. Check out the waterfall for 163.com. It’s pretty absurd. Here we have one of the most popular sites on the web and it’s opening up an astonishing 210 connections to serve its homepage! 72 of those connections are sharded across img[1-6].cache.netease.com, some shards across img[1-3].126.net, and a lot of connections on g.163.com. Glancing at the connection view, it seems that around 100 connections are utilized at the same time. This is obviously absurd and totally bypasses TCP slow start, since all of these connections will start with a server-side initcwnd of at least 3, and very possibly more, meaning an initial congestion window of 300 ! That’s just silly and totally busted, and you can see from CloudShark that the page load exhibits a number of self-inflicted congestion wounds:
Hostname sharding is a hack to work around HTTP’s lack of parallelism, but here the number of connections is simply too much, and it looks like it probably causes the page to load more slowly than it could. Site owners need to be careful with the number of hostname shards they use, as the increased parallelism may not always improve performance. The potential for congestion when using multiple connections is also higher nowadays due to the increased adoption of IW10. The real solution of course is to switch to a prioritized multiplexed protocol like SPDY and send all resources over as few connections as possible.