6 ms·
HPACK: the silent killer (feature) of HTTP/2
- grey-area 10y agoI see a lot of patches for nginx coming from cloudflare, how much of their infrastructure is based on nginx, anyone know any good articles on their internal setup?
- jgrahamc 10y agoI don't think we've every done a blog post on the overall architecture of a machine. But as of today it's a mixture of nginx (our own fork since nginx folks won't accept all our patches), rrdns (our own DNS server written in Go), a whole load of Lua (because we use OpenResty), a whole load of other services written in Go, ... Depending on the protocol (or version) traffic may or may not be served via nginx.
- grey-area 10y agoThank you, would love to see a blog post like that outlining the architecture you have ended up with and how it all fits together.
- garblegarble 10y ago>nginx (our own fork since nginx folks won't accept all our patches) Is there any interest in publishing this whole fork? I know you already publish separate modules to github, beyond that is there crossover with nginx plus functionality they don't want to accept?
- jgrahamc 10y agoThe problem with publishing it is that we have to maintain it and sometimes we put stuff in there that we wouldn't normally want to make public or it would be a pain to extract because it's linked to our infrastructure. Open sourcing stuff has a real cost. We do as much as we can.
- daenney 10y agoBut as of today it's a mixture of nginx (our own fork since nginx folks won't accept all our patches) Could you elaborate, within the limits that you're allowed, on the patches that got rejected? I'm curious as to what they were about and why they didn't make it in.
- jgrahamc 10y agoFor example, we support both SPDY and HTTP/2 and will do SPDY if an older client can't do HTTP/2. NGINX guys didn't want that. We tend to publish rejected stuff as patches: https://github.com/cloudflare/sslconfig/tree/master/patches https://github.com/cloudflare/sslconfig/tree/master/patches
- daenney 10y agoAwesome, thanks! I can sort of understand not wanting to maintain the SPDY code but I can see how that would be useful to CF to have. I'm a bit disappointed the chacha20 ones aren't making it in. I'm curious about the Dynamic TLS records patch. Could you or someone else that understands what that's doing elaborate on what's going on?
- j_s 10y agoDoes anyone have any practical experience with client certificates and HTTP/2? https://news.ycombinator.com/item?id=13022596 https://news.ycombinator.com/item?id=13022596 I had to abandon [client certificates] because of HTTP/2. If one site on the web server uses TLS client auth, and then you go to another site on the same server you receive HTTP 421 Misdirected Request, because of connection reuse. And almost none browser can deal with them correctly (or could not few months ago) - I'm looking at you Chrome, mobile Opera etc... -samsk 2016-Nov-28
- jlgaddis 10y agoChrome doesn't deal with (client) certificates well regardless of the HTTP version in use, to be honest.
- byuu 10y agoThis really seems like overkill to me. We've made HTTP/2 that much more complex to implement (a custom compression and dictionary not used anywhere else) to compress headers. And complexity always leads to fun new vulnerabilities. I guarantee at some point we'll see at least a DoS come out of this. I would add that it also consumes more resources to compress these headers (I know huffman is fast; but it's not as fast as plaintext), but you can probably cache a good portion of it, and then just encode the per-connection values at the end. Although I'd be surprised if Cloudflare has nginx doing that. Right now, my domain's HTTP header is 192 bytes: Content-Type: text/html; charset=utf-8 Content-Length: 3884 Connection: keep-alive Content-Security-Policy: upgrade-insecure-requests X-Content-Type-Options: nosniff X-Frame-Options: deny And more than half of it is just optional security enhancements. So now I'm going to compress that header so that it's ... what, 100 bytes? Even on my site that's incredibly lean and lacks images, it's around 20-30 KiB per page of content. Modern web pages now average being larger than the original DOOM video game (2301 KiB.) So we're doing all of this to chase roughly a 0.05% reduction in bandwidth per page? We're worrying about the spot on the carpet while ignoring the elephant in the room.
- jgrahamc 10y agoFrom the article: It is difficult to see, but we get 1.4% savings in the total egress HTTP/2 traffic. Header compression is cutting our overall bandwidth for HTTP/2. While it does not look like much, it is still more than increasing the compression level for data would give in many cases. So, better to do this than try to further compress pages.
- byuu 10y agoThere's a pretty big disconnect between 0.05% and 1.4%. Believing their numbers would indicate their average page sizes end up being around 7 KiB, or their headers end up being gigantic 4 KiB+ monstrosities, both of which I have trouble believing. But it's still small. Instead of adding a large chunk of complexity to HTTP/2, how much of that 1.4% do you suppose could be gleaned by removing unnecessary headers like Date, Server, X-Powered-By, cf-ray (on Cloudflare), etc? I understand that for Cloudflare hosting/proxying others' sites, their options are limited and they have to forward their customers' headers along. But I still think adding all of this is a bad idea. Not that it matters of course, it's already done. The IETF basically rubber stamped SPDY.
- ape4 10y agoWhats with those header fields that start with a colon: :authority:blog.cloudflare.com :method:GET :path:/assets/images/cloudflare-sprite-small.png :scheme:https Isn't that going to confuse every header parser.
- pilif 10y agoThat's just a way to spell out the HTTP 2 request-line (its http/1 equivalent would be the very first line of the request like `GET / HTTP/1.0`) in human-readable form. No parser is ever going to parse these strings. HTTP2 supporting libraries see the well-known binary values and libraries without support for HTTP2 will fall-back to HTTP1 anyways where the human-readable form of the request-line is, well, just the request line itself.
- ape4 10y agoThanks, now I know.
- Matthias247 10y agoThey are called pseudo-headers. They are used to transfer the values of the traditional start line of requests and responses. As in HTTP/2 there is no such start line they are encoded like other headers, but are using the colon in front of the key to denote them as pseudo-headers. Each request must contain all the required pseudo headers (:method, :path, :scheme) - same for the response. And no - this doesn't confuse a header parser since they are not parsed with an HTTP/1 header parser but with the HTTP/2 header tranmission mechanism (HPACK - as shown in the article). Before handing the request to your traditional web app the HTTP/2 server would remove those values from the set of received header fields and instead put them into the request struct.
- matt4077 10y agoResponse #1: date:Wed, 07 Sep 2016 21:41:23 GMT expires:Wed, 07 Sep 2016 21:41:53 GMT Response #2: date:Wed, 07 Sep 2016 21:41:23 GMT expires:Thu, 07 Sep 2017 21:41:23 GMT > Although the two expires headers are almost identical, they can only be Huffman compressed, because they can't be matched in full. It seems like it'd be be an easy win to round expiry times to the nearest minute/hour/day. At least for requests such as these where that value is one year in the future.
- niftich 10y agoThis. For HTTP 1.1 clients, Cache-Control already overrides anything set in Expires (a header dating to HTTP 1.0), so losing some precision on an approximate guess far into the future that's bound to be ignored by most clients should be a sensible trade-off.
- ape4 10y agoI wonder if HPACK will discourage the creation of new headers... since they won't be in the static dictionary. Instead existing headers will be overloaded (not so pretty).
- kevincox 10y agoI doubt that because the information added would be similar in size. Contrast `Foo: old-value unrealted-option=bar` to `Unrelated-Option: bar`. There is almost no difference (only the overhead of another header in the protocol actually. They would have to get way more creative in the representation to get any real gains. Also the HTTP authors haven't been too worried about header size in the past so I doubt this will change just because we have a new protocol.
- thecompilr 10y agoThe dynamic dictionary can be very large if needed, and can fit many headers. They will be evicted eventually, but only after many requests have been made.
- rmdoss 10y agoI recommend watching this video by Fast.ly on some real metrics comparing HTTP/2 and HTTP/1: https://www.youtube.com/watch?v=0yzJAKknE_k https://www.youtube.com/watch?v=0yzJAKknE_k Overall, the performance gain is not as much (if any) compared to the hype we hear.
- youngtaff 10y agoIf it's the video I'm thinking of they ran a huge number of tests, introduced packet loss and saw some issues. There's a few challenges here… WebPageTest uses DummyNet to simulate packet loss and in a HTTP/1.x scenario the not all TCP connections in the test will experience packet loss, whereas all the HTTP/2 ones will. Now in the real world if there's packet loss on route how likey is it that TCP connections experience packet loss? Our H2 implementations are still young, this Cloudflare work is one example, until they made this patch nginx didn't support HPACK and there are other issues in other browsers and servers too. As the implementations mature and we understand how to make the most of H2 then performance gains will appear - there's already evidence from people like the FT that there are gains to be made now.
- jgrahamc 10y agoQuite. Real world experience beats synthetic tests. Shipping counts for a lot. In the time that some other competitors have been talking about HTTP/2 we've had it out for a year and have been experimenting and improving (server push, HPACK, ...). Clearly, HTTP/2 is not the one-size-fits-all-answer-to-everything, but it amuses me to see competitors not shipping, yet talking a good game. See this sort of thing with HTTP/2, IPv6, ...
- byuu 10y agoEvery time I look at the hype pages, it's always these unbelievably ridiculous edge cases. "Look at how much faster HTTP/2 is loading this page that is nothing but an array of 64 x 64 icons that are each 16x16 pixels!" -- well of course that's going to be slow with HTTP/1 if each icon is unique and not cached. But who does that? If that pathological case is yours, then sprite the icons and now it's one request, done.
- 10y ago
- merb 10y agothe worst thing of the spec is that it writes stuff like: An endpoint might choose to close a connection without sending a GOAWAY for misbehaving peers. But it does not define how a misbehaving peer could look a like. Or WINDOW_UPDATE or RST_STREAM frames can be received in this state for a short period after a DATA or HEADERS Actually it's really really hard to get such a time right. Since it's extremly depending on the client. Also the http/2 state machine is extremly complex vs. the statefulness of a http/1 client (no state machine at all). Also the spec gives a lot of weight to the server/client where they can treat some errors either as a stream only error or as a full error (i.e. goaway, reconnect/disconnect). Not sure if it is good at all. Push Promises are probably not even useful to the most servers/users. And also have a flaky specification. It's okai to send them between data frames, but it makes no sense to do it. WebSockets don't work over http/2 and even with a extension they would disconnect every 31-bit/2 streams (or less). I think that http/2 is a good thing, but at the moment I would rather count on http/2.1 that will get everything correct and made stuff significantly easier. P.S.: Hpack is probably the easiest to implement/get right
- Matthias247 10y agoI don't think performing a clean shutdown for misbehaving clients is that important, as they are misbehaving anyway. The only thing were it helps is for debugging the misbehaving application: The developer can see the error message and see something got wrong instead of only seeing a closed connection. In doubt closing the connection is probably always the simplest way to handle invalid situations, as libraries will always have to deal with that situation. Handling close/shutdown/goaway messages is much harder. I also don't consider frames which are received for already reset streams as a big issue. Just ignore them if they are for an unknown stream ID which is lower than the highest established one. However I agree there are a few rough edges in the HTTP/2 spec. The worst one for me are race conditions around SETTINGS negotiations. If one implementations wants to use a low window size or HPACK buffer size it must still cope with the fact that the remote might send more data before it knows about it - which it can only answer with a stream reset. This in turn might cause many clients to assume that the server is not working or shutting down and to create a new connection and try the same again. The only sensible way for SETTINGS in my opinion is to use the default settings or higher ones - which are unfortunatly so high that it makes HTTP/2 a poor fit for embedded or IoT applications, where it could otherwise shine due to the less demanding binary protocol. The other thing that I don't like too much are the headers in special header frames without flow control. Getting overall flow control correct (and avoiding that attackers can exploit this) is hard. And from a layering perspective it would have been much clearer if there would have been a lower layer which allows to create flow-controlled multiplexed byte streams and a higher layer which defines on how to transport headers and body data inside these streams. Now we have one big HTTP/2 layer which covers everything. But I guess that was done to get HPACK working. HPACK itself is IMHO ok.
- bsder 10y agoNo offense. But if you had a magic way to reduce HTTP headers to zero, it would have no impact on me as a user. The fact that a web page loads 40+ domains? Yeah, that's a problem. The fact that a web page prioritizes serving me an ad so everything blocks until it gets that ad? Yeah, that's a problem. The fact that a web page downloads 25 Megabytes of data? Yeah, that's a problem. HTTP headers getting compressed? Not even on my radar.
- schmichael 10y agoYour complaints about the web are valid but totally out of scope for the HTTP spec.
- bsder 10y agoAsking why everybody is wasting time on something THAT WILL HAVE NO IMPACT ON END USERS is quite in scope, thanks. This benefits a very small number of companies who manage to serve very small, highly optimized payloads and nobody else. And everybody else pays the cost in terms of complexity, security holes, and implementation bugs.
- schmichael 10y agoMore efficient protocols mean lower costs for those companies. Lower costs potentially means fewer ads to make the same amount of money. Not every technical advance needs to have a direct impact on end users to have a positive indirect effect.
- byuu 10y ago> This benefits a very small number of companies ... And everybody else pays the cost in terms of complexity, security holes, and implementation bugs. Yes, exactly!! SPDY, QUIC, et al are designed by Google for the Googles and Facebooks of the world. It is not prioritizing what most sites need most. Hell, most sites don't need this period. Optimizing even the most generous 1.4% that Cloudflare claims isn't going to have any meaning to sites ranked below 100,000 in Alexa (eg 99% of them.) They're not going to run out of bandwidth, and their traffic means they're only using ~3% of a $5/mo VPS. You want software and website monocultures? This is how you get it. Unbelievable complexity creep. All the fun we've had with OpenSSL vulnerabilities? Get ready for them in the new QUIC-HTTP/2 servers. TLS alone already basically makes it impossible to write your own web server anymore, but at least that's a necessary evil due to ISP and state actor spying abuses. If you're okay with a world where everyone has the choice between nginx or Apache, I guess that's fine. I'm not, though.
- aorth 10y agoGreat savings. It would be great to know which upstream version of nginx these "full" HPACK patches were merged to. Does anyone know?
- aorth 10y agoI had asked the same question on the blog post, and the author responded there saying the patches were not integrated into vanilla nginx yet, only "upstreamed" to the nginx-devel mailing list in December, 2015. https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2/ https://blog.cloudflare.com/hpack-the-silent-killer-feature-...
- heisenbit 10y agoSignificant smaller headers means significant smaller requests. That allows the client to inform the server in a shorter time more comprehensively which set of files are needed. Especially in the mobile use case where bandwidth in the up-link is limited and the channel is not always stable this may really improve user perceived performance. I don't worry about compression effort too much - deflate has been used for a long time.