Talks
Ruby, HTTP/2 and You

http://www.rubyconf.org.au

HTTP/2 is here.

The first major revision since 1997 to Hypertext Transfer Protocol on which so much of the modern information transfer relies, HTTP/2 could have an enormous impact on the way we write applications.

RubyConf AU 2017

00:00:08.880 All right, I think the right side is a little cropped, but hopefully it's not going to be a big deal. There was a time when there was no web. Tim Berners-Lee, a scientist at CERN, a large research institution in Geneva, came up with the idea in 1989 to have a system of documents that would connect to make sense of what is actually being written in the documents. The original schema is very simple: documents are texts, and texts are linked with hyperlinks to other documents, and so on.
00:01:05.400 In the year 2017, we can play with this if you believe it, and I will show you how using apple.com. Connecting to the port 80 of apple.com after the initial TCP handshake, we're going to ask for the document at the root of the server. The server starts responding with the document content, and at the end of the document, the server disconnects because there is nothing else to do. There was one document, and the content will tell you how the request actually went. Okay, there was no 404, and so on.
00:01:51.439 At the beginning of the 1990s, there was a protocol that was more prevalent, and it was called Gopher. If you're old enough to remember, it's an interesting topic why Gopher died and HTTP succeeded, but that's a talk for another story. Alright, the vendors started extending this simple HTTP implementation, and they began adding more and more features. They wanted to add images, audio, stylesheets, and things like that, and we ended up with HTTP 1.0 in 1996, and 1999 brought HTTP 1.1.
00:02:32.800 So what is HTTP 1.1? That's a mouthful. When I say 'HTTP', I mean 1.1. In a typical situation, it goes like this: here we have two timelines. On the left side, I have a laptop because that's a client; on the right hand side, we have an iMac because I don't have the emoji for the server. The time goes from top to bottom, and the data flows between them.
00:03:11.040 First, we will establish the TCP handshake, you know, the SYN, SYN-ACK, ACK. After that, the client starts asking for documents. If I say 'GET index.html', the server will respond. As the client reads the document, it realizes that it needs more resources, for example, style.css, app.js, and so on. The server will do the work and return the documents as they are needed. That's pretty simple. We can do this with HTTP again in the year 2017, and we have an initial TCP handshake followed by HTTP requests consisting of one or more headers because the Host is a required header.
00:04:02.079 The request will be followed by two pairs of carriage return line feeds. The server will return with a status line, the headers, followed by two pairs of carriage return line feeds, and then the document. At the end of the document, you'll notice that the TCP connection is kept alive. If you want to ask for more resources, you can do that following the same rules: the document request, the header, and so on.
00:04:54.280 So what are the characteristics of HTTP? This is interesting because it will tell you why we do certain optimizations. For example, we have plain text headers, which are very easy to read for humans, and we reuse the TCP connection because it saves time on doing the initial TCP handshake. If you don't have to do that over and over, you will gain performance. One important characteristic of HTTP is that requests are queued on the server in the order they are received. So you want to make sure that the critical things you want to render the page are requested first. Things that take longer, you want to handle later so that you don't force users to wait.
00:05:56.639 Another thing to note is that session data is transmitted with each request. Remember the original implementation was for just one document; one request meant one document, and there was no state involved. HTTP 1.1 has to accommodate for that. Browsers enforce certain rules regarding the number of connections on the client side, which forces us to do optimizations that I might get into later.
00:06:31.560 So what is HTTP/2? HTTP/2 is a much shorter way to say it for me, so I'm going to shorten it to H2. H2 is a new protocol based on an experimental protocol named SPDY from Google in 2009. It became the springboard for HTTP/2, which was published in 2015, and you can use it today as the standard.
00:07:20.400 Alright, so what does it look like? Here we have the same timeline: server on the right, client on the left. We start with a TCP handshake, and then we have the TLS (Transport Layer Security) handshake which will define what protocol to use. After the TLS handshake, the application data will start to flow. TLS is not strictly required for H2, but many vendors, including Chrome, Firefox, Safari, and Opera, require TLS because it facilitates Application Layer Protocol Negotiation (ALPN). This means that the client will request H2 if the server can support it.
00:08:05.760 If it's not possible, it will downgrade to HTTP/1.1 to continue the session. So what are the benefits of H2? First of all, we have binary headers, which humans probably can’t read anymore! Binary headers are compact and will save time during communication with the server. You can also compress headers very effectively with another RFC named HPACK. This allows you to reuse headers so that you don’t have to transmit cookies and session IDs every time. If something is omitted, certain assumptions can be made, and there are rules for this. As application developers, you might not have to worry about them, but this is a significant advantage for H2.
00:09:25.640 Another feature of H2 is multiple full-duplex connections, meaning that for each request, the server and client can talk independently. You don’t have to be blocked by other resources that may take a long time to process on the server. This allows you to have more flexibility in your programming. On the server side, there’s one more feature: server pushes. Servers can push resources according to specific rules. For instance, if you ask for a stylesheet, the server can push other resources, such as fonts or images, without waiting for the client to tell it to do so, assuming the client accepts it. While this can be wasteful since the rules might be suboptimal, it could provide a performance boost.
00:10:23.000 These are the basic features of H2. Now, let's take a look at what the tooling looks like. As mentioned earlier, browsers are mostly compliant; many major browsers require TLS but support H2. For instance, the only red item on the chart is Opera Mini. If you're using Chrome, you can check if any of your sessions in the browser are using H2. You can look at the number of connections, sites, and more.
00:11:02.720 So browsers are functioning well and supporting H2 effectively. What about CLI tools? My CLI tool of choice for HTTP and other protocols, like FTP, is cURL. cURL's H2 support is not particularly user-friendly just yet. Currently, H2 support is not readily available for many operating systems. On Ubuntu, for instance, it doesn’t come out of the box, nor does macOS up to El Capitan.
00:12:13.200 If you're on Fedora and you pass the flag '-V,' you'll see a long list of implemented features, and in the last line, you'll notice HTTP/2. On Ubuntu, you won't see it listed, nor will you on El Capitan. To get H2 support, you'll need to compile it from source. That means on Ubuntu, you'd need the 'nghttp2' package, which is the newer generation of HTTP/2. You can configure it from source, and if you're using Homebrew on macOS, you can install 'nghttp2' and pass a long configuration parameter.
00:12:50.280 Running it with '-V' will show that HTTP/2 is available. To test H2, you may need to use Google, as Apple doesn't support H2 yet. Passing a little '-V' option will reveal at the end of the listing that it's offering H2 through ALPN – Application Layer Protocol Negotiation. The client will ask the server if it can use H2, and if it’s not possible, it will fall back to HTTP/1.1.
00:13:52.880 As a Ruby developer, what can you do to improve things for H2? Remember there are good practices to follow not just for H2 but for HTTP/1.1 as well. First, you want to place assets on a content delivery network (CDN). There are many affordable solutions these days; you don’t have to use Akamai. If assets like images and stylesheets are closer to users geographically, you’ll improve performance. You also want to minimize DNS lookups since they can be costly.
00:14:25.760 Avoid redirecting HTTP requests since that represents wasted bandwidth. Working and then realizing you need to ask another server can incur a lot of waste best to avoid it if possible. However, changes to the rules will come with H2. You’ll want to check if your application platform can utilize it, as some, like Heroku, do not have that functionality yet.
00:15:01.760 You can split assets up with qualifications since if assets are small and don’t change often, they can be cached on the server for faster serving. However, if assets are too small or change too frequently, the performance gains may not be substantial. You don’t need subdomains anymore as app connections from client to server are fully duplex and there’s no limit on the number of connections you can make. Finally, always test performance across different servers; many implementations of H2 exist, and none seem to dominate in terms of documentation, implementation, or performance.
00:16:02.640 Important ones include H2O, supported by Fastly, and other offerings like Nginx and Tomcat which have adopted H2. Now, Ruby developers, what does an H2 server look like for HTTP? It’s primarily Rails or Sinatra with some implementations like dry-rb and Hanami, which are built on top of Rack. Rack has a very straightforward promise regarding data structures, providing a triple of status code, header hash, and response body.
00:17:02.560 However, this simplicity doesn't mesh well with H2's capability, which may not follow a complete request and response cycle. Some work remains on Rack. I know that Aaron Patterson did a proof of concept some years ago; however, it's not in the mainline yet, so we need work if we wish for Sinatra and Rails to support H2 in a reasonable time frame.
00:17:50.080 You can proxy to the H2 server upfront for reasonable performance in the meantime. For client code, there are two Ruby implementations of H2: one is ‘http2,’ written in pure Ruby; and another, 'DS9,' which is a wrapper around NG HTTP/2, created by Tender Love (Aon Patterson). Neither of these implementations downgrades to HTTP/1.1 if H2 is unavailable. Therefore, you should implement fallback logic in your client code if that is essential.
00:19:01.760 As time is coming to an end, let's recap our exploration of the features of HTTP 1.1 and H2 and how they affect our application decisions. By leveraging the strengths of H2, we can embark on the journey toward enhanced performance with H2 in the near future. Thank you!