HTTP/1 should die

By Philip Jones

Recently WebSocket support has been added to HTTP/2 (in RFC 8441), completing the feature set of HTTP/1 in HTTP/2. With this feature HTTP/2 can do everything HTTP/1 can do only faster. This article will show how HTTP/2 is faster by focusing on multiplexing.

Lets consider a fairly complex site to display an auction market. It is a single page app with a WebSocket connection for the recent bids that makes a bunch of API requests when the user chooses a different auction to participate in. In other words the user can watch an auction develop with updates over the WebSocket and then switch to another auction triggering API requests. Clearly given the nature of the data it should all be served over HTTPS.

This complex site can be reduced to a WebSocket connection that sends an update every second with the ability to trigger around 20 API calls on demand. This reduction is available in this repository, and when served the page consists of two buttons, the left opens the WebSocket connection and the right triggers 20 API calls.

HTTP/1.1 requires a dedicated connection for each request (although a connection can be re-used after a request has finished), requiring the cost of the connection setup (including DNS, TCP handshake and SSL handshake) to be paid more than once. In addition the browser will be limited to opening at most 6 connections at a time, meaning the rest will be blocked until the first 6 complete.

Figure 1: HTTP/1.1 Connections timeline. The requests complete within 142ms.

As seen in figure 1 the requests complete within 142ms, however the large amount of red tells you the amount of time these requests spend blocked.

HTTP/2 improves on HTTP/1.1 by supporting multiplexing and pipelining, i.e. a single connection can now service all the requests concurrently. This means that the connection setup cost only has to be paid once. In addition the browser does not have to block any requests and can instead make them all at once and allow wait for the server to respond.

Figure 2: HTTP/2 connections timeline. The requests complete in 86ms.

As seen in figure 2 the requests now complete in 86ms, around half the time it took for HTTP/1.1. As is clear as well there is very little red and hence little blocking. In fact only the first few requests experience any blocking as the connection is established.

HTTP/2 alone makes a huge 62ms difference in the net time to complete the requests, however the browser is still blocked establishing the connection. As seen in figure 2 this takes around 10ms.

The complex site being considered requires a WebSocket, which means there is a persistent connection. As WebSockets can now be served over HTTP/2, the requests can also be multiplexed over this connection meaning there is no additional cost to establishing a connection.

Figure 3: Timeline for HTTP/2 requests with an existing WebSocket connection. The requests complete in 69ms.

This is shown in figure 3, there is no blocking, no red, as there is no need to establish a new connection. As expected the requests now complete in less time, roughly as expected the time spent establishing the connection.

HTTP/2 makes a huge difference to the fairly complex site considered in this article, reducing the total time by around 50%. This is likely to make huge difference to the user experience, with the addition of HTTP/2-WebSockets also making a small but noticeable gain. This difference will increase as the quality of the connection decreases, and hence the cost of setting up a connection increases.

WebSocket support in HTTP/2 is very new, the RFC was published in September 2018, Firefox (65) supports it as of late January 2019, and Chrome support is behind a flag. Server wise Hypercorn is the only open source library I can find (in January 2019) that supports HTTP/2 WebSockets.

With WebSocket HTTP/2 support there is nothing that HTTP/1.1 can do that HTTP/2 cannot. In addition HTTP/2 is much quicker. With support for HTTP/2 only likely to grow and improve, now is the time to switch.