Chapter 4: HTTP/2 — The Transport Foundation
gRPC is built entirely on HTTP/2. You cannot understand gRPC's behavior — its multiplexing, streaming, flow control, or header handling — without understanding HTTP/2. This chapter gives you that foundation.
Why Not HTTP/1.1?
HTTP/1.1 (1997) has fundamental limitations that make it unsuitable for high-performance RPC:
HTTP/1.1 Problems
- Head-of-line blocking — request B waits for response A to complete
- No multiplexing — one request per connection at a time
- Redundant headers — same headers (cookies, user-agent) sent with every request
- Text-based — headers are ASCII text, wasteful to parse
- No server push — server can't send data without a request
HTTP/2 Core Concepts
1. Binary Framing Layer
HTTP/2 is binary, not text. All communication is split into frames — small binary messages.
// HTTP/1.1 (text)
GET /users/123 HTTP/1.1\r\n
Host: api.example.com\r\n
Accept: application/json\r\n
\r\n
// HTTP/2 (binary frame)
┌─────────────────────────────────────┐
│ Length (24 bits) │ Type (8) │ Flags (8) │
├─────────────────────────────────────┤
│ R │ Stream Identifier (31) │
├─────────────────────────────────────┤
│ Frame Payload ... │
└─────────────────────────────────────┘
Frame types that matter for gRPC:
| Frame Type | Purpose | gRPC Usage |
|---|---|---|
| HEADERS | HTTP headers (compressed) | Method, path, metadata |
| DATA | Request/response body | Protobuf-encoded messages |
| RST_STREAM | Cancel a stream | RPC cancellation |
| SETTINGS | Connection configuration | Max concurrent streams, window size |
| WINDOW_UPDATE | Flow control | Backpressure in streaming |
| GOAWAY | Graceful shutdown | Server draining |
2. Streams, Messages, and Frames
- Connection — one TCP connection between client and server
- Stream — a logical bidirectional channel within the connection (identified by an integer ID)
- Message — a complete request or response (composed of one or more frames)
- Frame — the smallest unit of communication (9-byte header + payload)
Each gRPC call = one HTTP/2 stream. A streaming RPC with 1000 messages = one stream with 1000 DATA frames. Multiple concurrent RPCs = multiple streams on the same connection. This is why gRPC can handle thousands of concurrent RPCs on a single TCP connection.
3. Multiplexing
Multiple streams share one connection. Frames from different streams are interleaved:
// On the wire (one TCP connection):
[Stream 1 HEADERS] [Stream 3 HEADERS] [Stream 1 DATA] [Stream 3 DATA]
[Stream 5 HEADERS] [Stream 1 DATA] [Stream 3 DATA] [Stream 5 DATA] ...
// Each stream is reassembled independently by the receiver
This eliminates HTTP/1.1's head-of-line blocking at the application layer. (TCP-level HOL blocking still exists — that's what HTTP/3/QUIC solves.)
4. Header Compression (HPACK)
HTTP headers are repetitive. HPACK compresses them using:
- Static table — 61 common headers pre-defined (":method GET", ":status 200", etc.)
- Dynamic table — headers seen in this connection are indexed and referenced by number
- Huffman encoding — remaining values are Huffman-coded
Result: after the first request, subsequent requests send headers as just a few bytes (index numbers).
// First request: full headers sent (~200 bytes)
:method: POST
:path: /mypackage.MyService/MyMethod
:authority: server.example.com
content-type: application/grpc
te: trailers
grpc-timeout: 5S
// Second request to same service: mostly index references (~10 bytes)
// Only the path and timeout might differ
5. Flow Control
HTTP/2 has built-in flow control at two levels:
- Connection-level — total bytes allowed across all streams
- Stream-level — bytes allowed for each individual stream
The receiver advertises a window size (how many bytes it's willing to accept). The sender must not exceed it. When the receiver processes data, it sends WINDOW_UPDATE frames to open the window.
Flow control is how gRPC implements backpressure in streaming. If a server-streaming RPC produces data faster than the client can consume it, the client's window fills up, and the server automatically slows down. No application-level buffering needed.
6. Server Push (Not Used by gRPC)
HTTP/2 allows servers to push resources before the client requests them. gRPC does NOT use this feature. It's mainly for web browsers (pushing CSS/JS alongside HTML).
How gRPC Maps to HTTP/2
Every gRPC concept maps directly to HTTP/2:
| gRPC Concept | HTTP/2 Mechanism |
|---|---|
| RPC call | One HTTP/2 stream (POST request) |
| Request message | DATA frame(s) with length-prefixed protobuf |
| Response message | DATA frame(s) with length-prefixed protobuf |
| Metadata (headers) | HEADERS frame (initial) |
| Trailing metadata | HEADERS frame (trailers) — contains grpc-status |
| Cancellation | RST_STREAM frame |
| Deadline | grpc-timeout header |
| Streaming | Multiple DATA frames on one stream |
| Channel | One HTTP/2 connection (or pool) |
A Complete gRPC Call on the Wire
gRPC uses HTTP/2 trailers (headers sent AFTER the body) to convey the RPC status code. This is unusual — most HTTP APIs put the status in the initial response headers. gRPC can't do that because in streaming, the server doesn't know if the RPC will succeed until it's done sending all messages. This is why gRPC requires HTTP/2 — HTTP/1.1 doesn't support trailers reliably.
Connection Management
gRPC maintains long-lived HTTP/2 connections:
- One connection per channel (by default) — handles thousands of concurrent RPCs
- PING frames — keepalive mechanism to detect dead connections
- GOAWAY frames — graceful shutdown (server tells client to stop sending new requests)
- MAX_CONCURRENT_STREAMS — server limits how many RPCs can be active simultaneously
HTTP/2 Limitations (and HTTP/3)
HTTP/2 still runs on TCP, which has one remaining problem: TCP-level head-of-line blocking. If a TCP packet is lost, ALL streams on that connection stall until retransmission.
HTTP/3 (QUIC) solves this by running on UDP with per-stream loss recovery. gRPC is experimenting with HTTP/3 support, but HTTP/2 remains the standard.
- HTTP/2 gives gRPC: multiplexing, binary framing, header compression, flow control, streaming
- Each gRPC call = one HTTP/2 stream. Many calls share one TCP connection.
- gRPC uses trailers for status codes — this is why it requires HTTP/2
- Flow control provides automatic backpressure in streaming RPCs
- HPACK compression makes repeated metadata nearly free