One of the first things we noticed when using HttpWatch in Firefox 13 was that Google servers do not compress content in SPDY responses:
HTTP compression is usually the most important optimization technique a site can use because it drastically reduces the download size of textual resources such as HTML. It therefore seems surprising that the Google servers do not use it with SPDY responses to Firefox.
Normally, a browser indicates that it supports content compression using the Accept-Encoding request header. Firefox 13 doesn’t send this header in SPDY requests. Presumably, Mozilla believes it is not required:
Perhaps, it is the lack of this header that prevents the SPDY enabled Google servers from returning compressed content.
Twitter’s SPDY implementation takes a different approach. It assumes that if the browser supports SPDY then by implication it also supports compression:
So why do Mozilla and Twitter have a different approach to Google over SPDY content compression? The difference is probably down to the way they have interpreted the relevant sections of the SPDY protocol definition.
The Name/Value Header Block is a section of the SYN_STREAM, SYN_REPLY, and HEADERS frames used to carry header meta-data. This block is always compressed using zlib compression. …
However, for data compression it’s not so easy to work out what is required. The main section about content compression reads as follows:
4.7 Data Compression
Generic compression of data portion of the streams (as opposed to compression of the headers) without knowing the content of the stream is redundant. There is no value in compressing a stream which is already compressed. Because of this, SPDY initially allowed data compression to be optional. We included it because study of existing websites shows that many sites are not using compression as they should, and users suffer because of it. We wanted a mechanism where, at the SPDY layer, site administrators could simply force compression – it is better to compress twice than to not compress.
Overall, however, with this feature being optional and sometimes redundant, it was unclear if it was useful at all. We removed it from the specification.
That suggest that content compression is optional but does say if the client must support it.
In section 3.2.1 there’s a statement that supports the Twitter/Mozilla approach:
User-agents MUST support gzip compression. Regardless of the Accept-Encoding sent by the user-agent, the server may always send content encoded with gzip or deflate encoding.
However, the Overview section seems to imply that the normal Accept-Encoding / Content-Encoding handshake should be used:
SPDY attempts to preserve the existing semantics of HTTP. All features such as cookies, ETags, Vary headers, Content-Encoding negotiations, etc work as they do with HTTP; SPDY only replaces the way the data is written to the network.
The most sensible approach seems to be the one adopted by Mozilla and Twitter. It seems inconceivable that a SPDY aware client would not support content compression given that compression is always used for the headers.
The advantage of forcing all SPDY clients to support content compression is that the Accept-Encoding header is redundant and can be dropped saving a few bytes in each request message.
Things are happening fast at Mozilla. Although Firefox 4 was only released three months ago, Firefox 5 is only days away from final release. We can also expect to see versions 6 and 7 later this year.
One of the major performance related changes in Firefox 5 is an improvement in the way that keep-alive HTTP connections are re-used. Previously, there was a simple FIFO queue. So if Firefox ever tried to reuse a TCP connection it would simply use the connection that had been idle for the longest period of time.
However, not all connections are equal. Connections that have transmitted the most data are likely to be faster than those that have only received a small amount of data. This effect is caused by the congestion window mechanism in TCP.
To find out more please take a look at John Rauser’s excellent and entertaining talk at last year’s Velocity conference:
One of the major changes in Firefox 5 is that it now sorts the idle connections by congestion window size. Connections with the highest congestion window will be used first as described in the related bug report:
Right now the idle persistent connection pool is a FIFO.
What really distinguishes different connections to the same server is the size of the sending congestion window (CWND) on the server. If the window is large enough to support the next response document then it can all be transferred (by definition) in 1 RTT.
Connections with smaller windows are going to be limited by the RTT while they grow their windows.
All else being equal, which as far as I can tell it is, we want to use the big ones. We cannot directly tell what the server’s CWND is of course, but the history of the connection provides a clue – connections which have moved large flights of data (single responses, or aggregate pipelines of responses) will have given the server the best chance for opening that window in the past.
We’ve just updated HttpWatch to work with Firefox 5 beta 5 and decided to see if we could measure any performance gain from this change. Initially, we were disappointed to find no obvious improvement. This was probably because the use of up to six connections per host name allows a fair amount of averaging out of the congestion window. Also, even if a re-used connection is particularly fast its effect may be swamped by the other resources being downloaded at the same time.
The blog post that originally described the benefit of the ordering of connections by congestion window size used a particularly scenario:
Using an experiment designed to show the best case, the results are better than I expected for such a minor tweak. This was my process:
- construct a base page mixed with several small and several large images plus a link to a 25KB image. There are 6 objects on the base page.
- load the base page – FF4 will use six parallel connections to do it
- click on the link to the 25KB image – this will use an idle persistent connection. Measure the performance of this load.
Based on this we tried the same sort of process. First opening the HttpWatch Overview page and then clicking on a link to open a full resolution screen shot:
The performance benefit we measured in this scenario was substantial. We consistently found that the screenshot image loaded about twice as fast in Firefox 5 as it did in Firefox 4.
Here’s the screen shot image being loaded in Firefox 4:
and then in Firefox 5:
With HttpWatch it’s possible to track how the browser uses connections. You can do this by adding the Client Port column to the main grid. Each new TCP connection will use a different local TCP port and this is a handy way to see how connections have been used on a page.
In Firefox 4 you can see that the screen shot image was loaded on the first connection that became idle:
This connection hadn’t done much work so its congestion window would have been relatively small.
In Firefox 5, the screenshot image was downloaded using the connection that had loaded the largest amount of data on the previous page. It would have a much larger congestion window and would therefore be able to download the image much more quickly:
Although, this relatively simple change in Firefox 5 typically didn’t make much difference in certain scenarios the performance improvement can be dramatic.
So how does IE 9 compare? It appears to use the same FIFO algorithm as Firefox 4 with similar loading times:
We recently moved our blog from a Jumpbox VM to Windows 2008 R2 using the Microsoft Web Platform Installer. It makes setting up WordPress a doddle on Windows as it automatically installs and configures PHP, MySQL, IIS and WordPress in a couple of easy steps:
One performance benefit we got immediately was that HTTP compression was enabled by the installer in IIS 7.5 reducing the download size of any text based content:
In true dogfooding style we decided to use HttpWatch to look for some other easy performance gains. The first problem evident from the waterfall time chart was how the images in a typical blog post dominate the download process. Here’s the empty cache visit to the blog as seen by HttpWatch:
The relatively slow download of the blog post images is due to the fact that we’re in the UK, but our servers are in the US. It doesn’t really matter how fast an internet connection you use, the latency introduced by distance always has an effect on download speeds.
Content Delivery Networks (CDNs) provide a solution to this problem. They have servers located around the world that are able to serve cached content to web users with lower latency. We’re already a customer of MaxCDN so we fired up the control panel and created a new pullzone CDN that would serve content from our blog:
For convenience was also set up a new DNS entry for blogcdn.httpwatch.com that points at the MaxCDN subdomain:
We prefer to do that so that if there’s ever an issue with the CDN we can quickly point the CNAME back to the original source of the files.
The next step was to get WordPress to use the new hostname for the images we include in each blog post. There are several wordpress plugins that can do this but we settled on using CDN Rewrites as it allowed us to enter one simple rule:
This change caused a significant difference in the page load time:
Using a CDN like this provided two performance related benefits: