How HTTP/2 works
HTTP/2 solves HTTP/1.1's head-of-line blocking with multiplexed streams, binary framing, HPACK header compression, and server push. Learn how these mechanisms work and when they actually help.
The Problem Statement
Interviewer: "Your team is running an HTTP/1.1 web application. Users complain that the page loads slowly even though each individual API call returns in 20ms. You look at the network waterfall in Chrome DevTools and see that most requests are sitting idle, waiting for earlier ones to finish. What is happening, and how does HTTP/2 fix it?"
This question tests three things: whether you understand HTTP/1.1's head-of-line (HOL) blocking at the application layer, whether you can explain how HTTP/2's multiplexed streams solve it, and whether you know the remaining HOL blocking problem at the TCP layer that HTTP/3 exists to fix.
Candidates often stumble here because they know HTTP/2 is "faster" but cannot explain the mechanism. The interviewer wants you to trace a request through the binary framing layer, explain how multiple streams share one TCP connection without blocking each other, and articulate the tradeoffs that remain.
HTTP/2 was standardized as RFC 7540 in 2015, based on Google's SPDY protocol. As of 2024, it is used by over 65% of all websites and is the default protocol on every major CDN, cloud load balancer, and web server. Understanding it is foundational knowledge for any system design interview.
Clarifying the Scenario
You: "Before I walk through the fix, let me clarify a couple of things."
You: "When you say the requests are sitting idle, I assume we are seeing the effect of the browser's per-origin connection limit in HTTP/1.1, which is typically 6 concurrent TCP connections per domain. Requests beyond that queue behind active ones."
Interviewer: "Exactly. That is the symptom."
You: "Got it. And should I focus on how HTTP/2 solves this at the protocol level, or do you also want me to cover deployment considerations like TLS requirements and server push?"
Interviewer: "Start with the protocol mechanics, then briefly touch on what works and what did not work in practice."
You: "OK, I will structure my answer in three parts: first, why HTTP/1.1 has the HOL blocking problem and why tricks like domain sharding only mask it. Second, how HTTP/2's binary framing and multiplexed streams solve it. Third, the HPACK header compression system and why there is still a HOL blocking problem at the TCP layer that HTTP/3 addresses."
My Approach
I break this into five parts:
- The HTTP/1.1 HOL blocking problem: One request per TCP connection at a time, browsers limited to 6 connections per origin, and why pipelining never worked in practice.
- Binary framing layer: HTTP/2 replaces text-based parsing with a binary frame format that enables multiplexing.
- Multiplexed streams: Multiple request/response pairs interleaved over a single TCP connection, with per-stream flow control.
- HPACK header compression: A purpose-built compression scheme that reduces header overhead from kilobytes to bytes by using static tables, dynamic tables, and Huffman encoding.
- The remaining TCP-layer HOL blocking: Why a single packet loss still stalls all streams, and how HTTP/3 (QUIC) removes this final bottleneck.
The core insight is that HTTP/2 does not make individual requests faster. It makes many concurrent requests efficient by eliminating the artificial serialization that HTTP/1.1 imposed. A page that needs 80 resources no longer needs 80 round-trips spread across 6 connections. It needs one connection.
Let me give you the numbers. A typical modern web page loads 80-120 resources (HTML, CSS, JS bundles, fonts, images, API calls). With HTTP/1.1's 6-connection limit, the browser processes these in waves of 6. Each wave costs at least one round-trip (50-100ms on broadband, 200-400ms on cellular). That means 14-20 waves, adding 700ms-8s of pure serialization delay before accounting for actual transfer time. HTTP/2 collapses this to a single connection where all 80 requests fly simultaneously.
HTTP/2 does not change the HTTP semantics. Methods, status codes, headers, and cookies work exactly the same. What changes is the transport: text-based serial communication becomes binary multiplexed communication. Your application code does not change. Your HTTP libraries handle the protocol negotiation automatically.
The Architecture
Here is the full picture of how HTTP/2 handles multiple requests over a single TCP connection. The binary framing layer is the key innovation: it splits each request and response into frames, tags them with a stream ID, and interleaves them on the wire.
Walk through what happens when the browser loads a page:
- The browser opens a single TCP connection to the server and completes the TLS handshake.
- It sends all four requests simultaneously as HEADERS frames, each tagged with a unique odd-numbered stream ID (clients use odd IDs, servers use even).
- The binary framing layer splits each request and response into small frames (typically 16KB each).
- Frames from all streams are interleaved on the single TCP connection. A DATA frame for stream 1 can be followed immediately by a DATA frame for stream 3.
- The server processes all requests concurrently and sends response frames back, also interleaved.
- The client's framing layer reassembles each stream from its tagged frames.
The result: no request blocks another. The browser gets all four responses as fast as the server can produce them, without the artificial 6-connection bottleneck.
HTTP/2 stream IDs are odd for client-initiated streams and even for server-initiated streams (like server push). Stream 0 is reserved for connection-level control frames like SETTINGS and WINDOW_UPDATE.
Multiplexed Streams and Binary Framing
This is the heart of HTTP/2. Let me show how frames from different streams interleave on the wire, and why this is fundamentally different from HTTP/1.1 pipelining.
In HTTP/1.1, pipelining was supposed to fix this. The client could send multiple requests without waiting for responses. But it failed in practice because responses had to come back in order. If the first response was slow (a large image), it blocked all subsequent responses behind it. Most browsers disabled pipelining entirely.
HTTP/2 fixes this by making streams truly independent. Each frame is self-describing: it carries a stream ID, a type (HEADERS, DATA, PRIORITY, etc.), and flags (END_STREAM, END_HEADERS). The receiver uses the stream ID to reassemble each response independently.
Here is what a binary frame looks like:
| Field | Size | Purpose |
|---|---|---|
| Length | 3 bytes | Payload size (max 16,384 bytes default) |
| Type | 1 byte | HEADERS (0x1), DATA (0x0), SETTINGS (0x4), etc. |
| Flags | 1 byte | END_STREAM, END_HEADERS, PADDED, PRIORITY |
| Stream ID | 4 bytes | Which stream this frame belongs to |
| Payload | Variable | The actual header or body data |
The 9-byte frame header is tiny compared to HTTP/1.1's text-based headers, which could easily be 500+ bytes of repeated Host, User-Agent, Accept, and cookie headers on every single request.
Continue Reading with Premium
Unlock this article and every other in-depth system design guide on the platform with SDEpedia Premium.
Related Articles
How TCP delivers reliable, ordered byte streams: the three-way handshake, sequence numbers, flow control, congestion control, and why TCP behavior matters when designing distributed systems.
What actually happens in the TLS 1.3 handshake: ClientHello, ServerHello, key exchange, certificate verification, and how both parties derive symmetric session keys without ever transmitting them.