9 ms·
Performance Testing HTTP/1.1 vs. HTTP/2 vs. HTTP/2 and Server Push for REST APIs
- ncf_ 7y agoneat work! didn't notice it mentioned in the article but, would there be a processor load difference between the two?
- snek 7y agoOne of my favourite demos is https://http2.akamai.com/demo https://http2.akamai.com/demo
- mathisonturing 7y agoHTTP/1.1 is constantly ahead when I run it on mobile connected to my Home WiFi. Edit: /2 is faster when on first load. When I refresh, /1.1 is almost always faster.
- EugeneOZ 7y agoios, Safari, wifi (59 mbps on fast.com): http/2 is 10 times faster on first load, 2-3 times on subsequent.
- codefined 7y agoWindows, Firefox, Ethernet (220mbps on fast.com): https/2 is ~0.1s (1.02s /2 vs 1.11s /1.1) faster on first load and ~0.2s faster on future loads. I'm tempted to say there are diminishing returns as your internet gets faster (latency is ~11ms atm).
- rumanator 7y ago> HTTP/1.1 is constantly ahead when I run it on mobile connected to my Home WiFi. In the test I've ran right now, HTTP/1.1 took around 3x the time it took HTTP/2 to finish, even after refreshes.
- bsdetector 7y agoIt paints a misleading picture. When this demo first came out, it didn't have the right reply header to enable pipelining in the browser. Now it does, but browsers have removed pipelining support. Pipelining is a part of HTTP/1.1. If you download a firefox from before they removed pipelining you can enable it and you'll see that there's essentially no advantage to HTTP/2 for this demo. This demo could measure connection establishment time and bandwidth, and simulate pipelines. But I think they don't actually want you to know that even a 6-connection 1-deep pipeline is just about as good as HTTP/2.
- re 7y agoIt's interesting to see the impact that having the developer tools open has on performance, and whether the network tab is being shown or not. While HTTP2 is generally faster for me, opening the developer tools makes both significantly slower, and seems to have a larger impact on HTTP2, usually making it slower than 1.1, in both Firefox and Chrome.
- londons_explore 7y agoDeveloper tools internally proxies every request. The proxy interface it uses is a custom devtools protocol, and can't handle every part of http - for example, at assumes all post request bodies are delivered in one go rather than streamed. It also uses the same single JavaScript thread to proxy the requests as is used for rendering the devtools UI, which can't be great for performance.
- gatestone 7y agoAs credited there on the page, this was the orginal: https://http2.golang.org/gophertiles https://http2.golang.org/gophertiles
- The_rationalist 7y agoHas the performance gain that bring http3 on mainstream workloads been quantified/benchmarcked?
- time0ut 7y agoMany of my clients are behind MITM proxies that force a downgrade to 1.1, so I end up having to optimize for 1.1 and minimize total requests anyway. We've started down the path of GraphQL to aggregate requests, but it feels so counter productive (with respect to performance/effort).
- takeda 7y agoI really miss old Opera which correctly implemented HTTP pipelining[1] :/ [1] https://en.wikipedia.org/wiki/HTTP_pipelining https://en.wikipedia.org/wiki/HTTP_pipelining Edit: article also doesn't mention about keep-alive, in fact it explicitly states that HTTP/1.1 opens one connection per request which is not true. Makes me think that the HTTP/1.1 demo disables KA to make effect even more dramatic. Edit2: demos don't make actual network requests.
- Thaxll 7y agoIt's hard to know if it was correctly implemented knowing that other wouldn't implement it because of major issues.
- takeda 7y agoAs an Opera user from 2003 to 2016 (when they decided to drop Presto) I don't remember having any issues with it.
- bsdetector 7y agoHas anybody ever given any even halfway compelling evidence of pipelining breaking websites? Google didn't, Mozilla didn't. I believe there was one small banking site using a ten year old IIS that didn't load - but maybe pipelining was the least of the problems there. Another that sent the wrong images to mobile Safari, or mobile Safari displayed them wrong, but was fixed. Pipelining may not have been the technically best solution, but it certainly would have taken the impetus away from SPDY. If Mozilla had shown the courage to default to pipelining maybe the industry as a whole could have had some input on HTTP/2 instead of just rubber-stamping SPDY.
- toast0 7y agoThere's several bug reports attached to this bug: https://bugzilla.mozilla.org/show_bug.cgi?id=264354 https://bugzilla.mozilla.org/show_bug.cgi?id=264354 This probably could have been solved for HTTPS though, if you negotiate to http/1.1 via ALPN, then pipelining could be OK? Otherwise, http/1.1 with keepalive only should be used?
- mcguire 7y ago"Compound requests are by far the fastest. This indicates that my original guess was wrong. Even when caching comes into play, it still can’t beat just re-sending the entire collection again in a single compounded response." TCP is heavily optimized for shoving a single stream of bits across the wire. The other options have more overhead from multiple requests.
- userbinator 7y agoI think the most interesting thing about this test is that it shows HTTP/2 isn't always faster than 1.1 --- in the first test, h1 compound is just as fast as h2, and in the second, even slightly faster. Considering all the additional complexity that HTTP/2 introduces, that doesn't seem like any improvement. Also, "relative speeds" should really be "relative times" because otherwise the percentages imply the exact opposite. I was a little confused for a bit by that.
- treve 7y agoI fixed the captions, thank you. My biggest surprise was that compound requests are still faster, even if they need to send 10 times as much data (the 90% cached case).
- rumanator 7y ago> in the first test, h1 compound is just as fast as h2 That's because HTTP/2 auto-compounds multiple requests to send in the same connection, thus there is no surprise there. The main advantage of HTTP/2 is that it ensures that we can get the same benefit of compound data transfers in a completely transparent manner, without bothering to rearchitect how clients and servers operate. > Considering all the additional complexity that HTTP/2 introduces, that doesn't seem like any improvement. This assertion completely misses the whole point of HTTP/2, and why it's a huge improvement over HTTP/1.1.
- voidlogic 7y agoAlso of note is having to terminate a single TCP/TLS connection per client vs one for every concurrent client request! Even if you are using a middle man like a CDN doing HTTP 1.1 pooling this is still reducing the established TCP/TLS connections by an order of magnitude or more.
- treve 7y ago> The main advantage of HTTP/2 is that it ensures that we can get the same benefit of compound data transfers in a completely transparent manner, without bothering to rearchitect how clients and servers operate. Yea this assertion is spot-on, but sadly HTTP/2 still has enough overhead that if speed really is the most important requirement, compounding data is still better. I was hoping the difference would be at least smaller.
- 3xblah 7y agoIs there such a thing as an "HTTP connnection". Maybe the author means "TCP connection" Maybe "Quick UDP Internet Connection" (QUIC) in the case of HTTP/2 QUIC appeared after the publication of another UDP-based, congestion-controlled protocol, CurveCP and used ECC by the author of CurveCP QUIC seems tied to HTTP, whereas CurveCP, initially used for DNS, is application-agnostic What are some other applications besides web browsers and web servers that are using QUIC
- tialaramex 7y agoYes there is such a thing as an HTTP connection. So now you learned something valuable. Each connection consists of one or more HTTP requests. In HTTP/1.1 in practice you must complete an entire request and response before beginning another. (Edited to add, since you did) There are two things you might mean by QUIC. Google's test protocol QUIC (these days often called 'gQUIC') was developed and deployed in-house, and has all sorts of weird Google-isms, it's from the same period as their SPDY which inspired HTTP/2. gQUIC is no longer under further development. They handed the specification over to the IETF years ago, and the IETF's QUIC Working Group is working on an IETF standard QUIC which will replace TCP for applications that want a robust high performance encrypted protocol. HTTP over QUIC will be named HTTP/3 and will offer most of the same benefits as HTTP/2 (which is HTTP over TLS thus over TCP/IP) but improve privacy and optimise some performance scenarios where head-of-line blocking in TCP was previously a problem - probably some time in 2020 or 2021. The HTTPbis (bis is a French word which has similar purpose in addresses as the suffix letter a would in English e.g. instead of 45a you might live at 45bis) working group is simultaneously fixing things in HTTP/2 and preparing for HTTP/3.
- 3xblah 7y ago"... where head-of-line blocking in TCP was previously a problem..." Has anyone ever shared a demo where we can see this occuring with pipelined HTTP/1.1 requests I have been using HTTP/1.1 pipelining -- using TCP/TLS clients like netcat or openssl -- for many years and I have always been very satisfied with the results Similar to the demo in the blog post, I am requesting a series of pages of text (/articles/1, /articles/2, etc.) I just want the text of the article to read, no images or ads. Before I send the requests I put the URLs in the order in which I want to read them. With pipelining, upon receipt I get automatic catenation of the pages into one document. Rarely, I might want to split this into separate documents using csplit. HTTP/1.1 pipelining gives me the pages in the order I request them and opens only one TCP connection. It's simple and reliable. If I requested the pages in separate connections, in parallel, then I would have to sort them out as/after I receive them. One connection might succeed, another might fail. It just becomes more work.
- yoz 7y agoFascinating work, thank you! Possible issue: have I misread it, or is the explanation of HTTP/3's advantages entirely missing from this section[1]? It's in the section header, but HTTP/3 isn't mentioned again until "The perfect world"[2] and that section doesn't clarify how HTTP/3 matters to the discussion. [1] https://evertpot.com/h2-parallelism/#http2-and-http3 https://evertpot.com/h2-parallelism/#http2-and-http3 [2] https://evertpot.com/h2-parallelism/#the-perfect-world https://evertpot.com/h2-parallelism/#the-perfect-world
- treve 7y agoYea you are right. HTTP/3 is not really yet, at least for Node.js. Maybe worth revisiting this in a year or so. I appreciate the criticism though.
- mgraczyk 7y agoPossibly so obvious it's not worth pointing out, but client side caching is also important for server side scaling. If your clients cache X% of responses, you can generally get away with ~X% fewer API servers. So even if client performance doesn't improve much you should probably still cache.
- ggm 7y agoStory told well, comprehensible. Thanks!
- beders 7y agoMaybe I missed it in the article, but is gzip-compression enabled? If so, the total amount of data transmitted will be quite different when a compounded response is compared to individual ones.
- candu 7y agoThe thing that jumps out at me about HTTP/2: even if your browser can send N parallel requests for different entities, you're still making N database queries and incurring N request overheads. This means that every layer of your stack has to be reorganized and optimized around HTTP/2 traffic patterns...or you can just batch requests as before, and save that overhead. It makes me think that the N entities problem isn't actually the most promising use case for HTTP/2...
- littlecranky67 7y agoI don't think most resources in todays web are database-dependent. It is mostly static content (images, videos, scripts, stylesheets etc.) that are large in filesize. A single resource, however, might trigger a multitude of db queries (think calling a REST service endpoint). Anyways, HTTP/2 allows multiplexing and waiting a single resource won't stall any other requests, which can be sent whenver they are ready.
- treve 7y agoThis can be partially solved with HTTP2 Server Push
- mehrdada 7y agoIf you care about performance, gRPC/Protobufs would be something to look at and compare against.
- ricardobeat 7y agoOut of curiosity, I implemented the same using websockets. You'll obviously need a real implementation of a request-response interface, but this will do for the test: // server ws.on('message', msg => { switch (msg) { case 'collection': return ws.send([...generate 500 links ...]) case 'item': return ws.send(...generate item...) } }) //client ws.send('collection'); ws.onmessage = e => { const msg = JSON.parse(e.data) switch (msg.type) { case 'collection': collection.forEach(item => ws.send('item')) case 'item': items.push(item); } } It finishes in 140-150ms, around the same time as the best HTTP version. That's without any caching and the client requesting each of the 500 items, when in fact the server could just push them. I'm surprised WS is not used more often for data exchange. EDIT: actually ~50ms after removing the console.log() I added for each message...
- maxpert 7y agoWould be nice if you can put up a demo page some where.
- hliyan 7y agoDo load balancers and reverse proxies play well with websockets?
- slamb76 7y agoYes but only if they are at layer 3 implementation support is variable
- londons_explore 7y agoLoad balancing websockets can be tricky because an individual socket could last many hours. That means when you do a software update, you need to leave the old version running for many hours. Same applies with http, but an individual request tends not to take many hours.
- throwawaysea 7y agoGreat article; the demos were very intuitive. What about alternatives to HTTP entirely? Why not rely on lower level protocols/abstractions if performance is such a concern now?
- hatch_q 7y agoThey would be more intuitive if they were actually demos, not animations that don't actually do any requests.
- alexghr 7y agoVery interesting article! I wonder how compound requests scale as body size increases. Would we see individual HTTP2 requests become faster after items become "large enough"?
- littlecranky67 7y agoI call BS on the benchmarks AND the theoretical analysis. Every time I read those HTTP/X benchmarks, people don't mention TCP's congestion control and seem to just ignore it in their analysis. Well, you can't. At least if you call "realistic conditions". Congestion control will introduce additional round trips, depending on your link parameters (bandwidth, latency, OS configuration like initcwnd etc.) and limit your bandwidth on the transport layer. And based on your link parameter, 6 parallel TCP connections might achieve a higher bandwidth on cold start because the window scaling in tcp slow start is superior than in a single tcp connection used by HTTP/2. Additionally, the most common error people do while benchmarking (and i assume the author did too) is to ignore the congestion control's caching of the cwnd in the tcp stack of your OS. That is, once the cwnd is raised from usually 10 mss (~14,6kb for most OSes and setups), your OS will cache the value and re-use the larger cwnd as initcwnd when you open a new tcp socket to the same host. So if you do 100 benchmark runs, you will have one "real" run, and 99 will re-use the cwnd cache and produce non-realistic results. Given the author didn't mention tcp congestion control at all and didn't mention any tweaks to the tcp metrics cache (you can disable or reset it through changing /proc/sys/net/ipv4/tcp_no_metrics_save on linux) I assume all the measured numbers are BS.
- jpambrun 7y agoI have use http2 and http1 with domain shardind extensively and the advantage of http2 multiplexing cannot be denied. TCP connection overhead is negligible (other than the tsl negotiation maybe) and is not even really a factor.
- littlecranky67 7y agoTCP congestion window scaling is not negligible, especially not in high-latency environments. The initcwnd is usually 14,6kb(10x MSS of 1460 byte in common DSL setups), meaning a server can only send those 14,6 kb until the connection is stalled and an ACK is received (=1x roundtrip). Google realized this and tried to get a kernel patch into Linux where the browser (or any userspace program) can manipulate the initcwnd. The patch got rejected, and thats basically why they came up with QUIC: To be able to build on UDP and implement congestion control and other stuff TCP usually does (ordering, checksumming etc) in userspace.