Head-of-line blocking at both the application and transport layer, multiplexing, keep-alive, and why connection reuse is the cheapest performance win you have.
Module F-6 — HTTP/1.1, HTTP/2, and HTTP/3
What this module covers: Given Module F-5's conclusion that round trips dominate, the natural next question is how well each protocol version uses a connection. This module covers HTTP/1.1's one-request-at-a-time limitation and the six-connections-per-origin workaround it forced, HTTP/2's binary framing and multiplexing, the TCP-level head-of-line blocking HTTP/2 could not fix, and how HTTP/3 sidesteps it by abandoning TCP for QUIC over UDP. It also covers the parts that surprise people in production: why multiplexing changes how load balancers distribute traffic, why HTTP/2 is what makes gRPC possible, and the cases where none of this matters at all.
The Problem: One Connection, One Request at a Time
HTTP/1.1's defining limitation is simple. A connection carries one request/response exchange at a time. Send a request, wait for the full response, then send the next. The specification does define pipelining — sending several requests without waiting — but responses must come back in order, so one slow response blocks everything queued behind it. In practice it was so poorly supported by intermediaries that browsers disabled it, and it's effectively dead.
That's head-of-line blocking at the application layer: one slow item delays every item behind it in the same queue.
Analogy: HTTP/1.1 is a single-lane road with no overtaking. If the truck in front is slow, everyone behind it is slow, regardless of how fast their cars are or how empty the road ahead looks.
Browsers worked around it by opening six parallel connections per origin — six lanes instead of one. That helped, and it introduced its own costs. Each connection pays a fresh TCP handshake, a fresh TLS handshake, and starts in slow start (Module F-5), and six connections competing for the same bandwidth means six congestion controllers each with an incomplete view. A page with 80 resources still queues them through six lanes.
Which produced the era of front-end workarounds you may remember, all of them there to dodge the connection limit rather than to make anything genuinely better:
- Domain sharding — serving assets from
img1.example.com,img2.example.comto get 6 connections per hostname, at the cost of extra DNS lookups and extra handshakes. - Sprite sheets — one image containing dozens, cut up with CSS, so one request replaced thirty.
- Bundling and inlining — concatenating all JS into one file, base64-inlining images, so that a change to one line invalidates the cache for everything.
Why this matters in production: every one of those techniques becomes harmful under HTTP/2, and plenty of build pipelines still do them. Under a multiplexed protocol, one giant bundle means a one-line change re-downloads the whole thing, and domain sharding forces extra connections that multiplexing was designed to eliminate. Protocol upgrades don't just make things faster; they invert previous best practices, which is precisely why "best practice" without a stated reason ages badly.
HTTP/2: Multiplexing Over One Connection
HTTP/2 keeps HTTP's semantics — methods, status codes, headers all mean the same thing — and replaces how they're framed on the wire.
Binary framing. Instead of newline-delimited text, HTTP/2 sends binary frames, each tagged with a stream ID. That single change enables everything else, because frames from different streams can be interleaved on one connection.
Multiplexing. Many concurrent requests share one TCP connection, and responses can come back in any order and interleaved. Head-of-line blocking at the application layer is genuinely gone — a slow response no longer blocks the others.
HPACK header compression. HTTP headers are repetitive and, with cookies, often larger than the body of a small API response. HPACK compresses them and maintains a dynamic table of previously-sent headers, so repeated headers cost a few bytes rather than a few hundred. On a page making 100 API calls with a 1 KB cookie, this alone saves ~100 KB of upstream traffic.
Stream prioritisation and flow control. Clients can signal that the stylesheet matters more than a below-the-fold image. Support has been inconsistent across servers and CDNs, so treat it as a hint rather than a mechanism you rely on.
Server push let servers send resources before they were requested. It's now effectively deprecated — Chrome removed support — because servers routinely pushed things clients already had cached, wasting bandwidth. 103 Early Hints covers the useful case (telling a client what to start fetching) without the guessing.
The result: one connection, one handshake, one congestion window that ramps up once and is then shared by everything. On a page with many small resources, this is a large win and the workarounds above become counterproductive.
What HTTP/2 Couldn't Fix: TCP-Level Head-of-Line Blocking
Here's the subtlety that justifies HTTP/3's existence, and it's a good example of a problem being pushed down a layer rather than removed.
TCP guarantees in-order, reliable delivery of a single byte stream. It has no idea that the stream contains interleaved HTTP/2 frames belonging to independent requests. So when one packet is lost, TCP holds back every byte that arrived after it until the retransmission arrives — because delivering them out of order would violate TCP's contract.
Sign in to keep reading
The rest of this module is free — sign in with Google to unlock it and track your progress.
Sign in & RegisterDiscussion
0Join the discussion