Back to Advanced Topics
Q41Question 41 of 41

Why does gRPC rely on HTTP/2 instead of HTTP/1.1, and what breaks with HTTP/1.1 (no multiplexing/streaming/binary)?

Key Concepts
  • gRPC depends on HTTP/2's stream multiplexing to run many concurrent RPCs over one TCP connection without head-of-line blocking.
  • HTTP/2's full-duplex bidirectional streaming enables gRPC's server streaming, client streaming, and bidirectional call types.
  • HTTP/2's binary framing layer matches gRPC's binary Protocol Buffers payloads and length-prefixed message framing.
  • gRPC sends the final status code in HTTP/2 trailers after the response body, which HTTP/1.1 does not support reliably.
  • HTTP/2's HPACK header compression reduces overhead for the many small metadata headers gRPC uses per call.
  • This HTTP/2 dependency is why browsers cannot speak native gRPC and need gRPC-Web with a translating proxy.
  • An HTTP/1.1-only proxy or incorrectly terminating load balancer silently breaks gRPC multiplexing and streaming.

Definition

gRPC needs HTTP/2's multiplexing, bidirectional streaming, binary framing, and trailers; HTTP/1.1 lacks all of these, so gRPC's streaming and concurrency model cannot run on it.
  • Stream multiplexing – HTTP/2 carries many concurrent, independent request/response streams over one TCP connection, which gRPC uses for concurrent RPCs without opening many connections.
  • Bidirectional streaming – HTTP/2 supports full-duplex data flow in both directions on the same stream, enabling gRPC's server, client, and bidirectional streaming calls.
  • Binary framing – HTTP/2's binary frame layer matches gRPC's binary Protocol Buffers and length-prefixed message framing for efficient transport.
  • Trailers – gRPC sends the final status code (grpc-status) in HTTP/2 trailing headers after the response body, which HTTP/1.1 does not support reliably.
  • HPACK compression – Header compression reduces per-call overhead for gRPC's metadata headers.

Imagine the line between the transfers desk and the accounts desk at National Bank of India. HTTP/1.1 is like a single phone line where you must finish one whole call before starting the next, and you cannot talk and listen continuously at the same time. HTTP/2 is like a modern switchboard on one wire that carries dozens of calls at once, each independent, and lets both sides talk simultaneously. gRPC was designed for busy, streaming, two-way conversations between desks, so it needs the switchboard. On the old single-call line, its streaming and concurrent-calls features simply cannot happen.

Understanding the Concepts

Why does gRPC need multiplexing?

HTTP/2 carries many logical streams over one TCP connection, each with its own stream ID, interleaved as binary frames. This lets a single gRPC channel run many concurrent calls without opening many connections and without one slow call blocking others. HTTP/1.1 handles one request/response at a time per connection, and pipelining suffers head-of-line blocking.

JAVA
package com.bank.client;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.concurrent.CompletableFuture;
import java.util.stream.IntStream;

public class MultiplexingDemo {

    public void concurrentCalls() {
        // ONE channel, ONE TCP connection
        ManagedChannel channel = ManagedChannelBuilder
                .forAddress("account-service", 9090)
                .usePlaintext()
                .build();

        // 100 concurrent calls over that single connection
        // HTTP/2 multiplexing handles them as independent streams
        var futures = IntStream.range(0, 100)
                .mapToObj(i -> CompletableFuture.runAsync(() -> {
                    // Each call is an independent HTTP/2 stream
                    getBalance(channel, "SAV" + i);
                }))
                .toList();

        CompletableFuture.allOf(
                futures.toArray(CompletableFuture[]::new)).join();
        channel.shutdown();
    }

    private void getBalance(ManagedChannel channel, String id) {
        System.out.println("Balance for " + id);
    }
}

Why does gRPC need bidirectional streaming?

gRPC's server streaming, client streaming, and bidirectional streaming need the ability to send a sequence of messages within a single logical call, in both directions. HTTP/2 DATA frames can flow in both directions on the same stream until it is closed. HTTP/1.1 models one request then one response, with no true full-duplex streaming.

JAVA
package com.bank.grpc;

import io.grpc.stub.StreamObserver;
import java.math.BigDecimal;

public class StatementGrpcService
        extends StatementServiceGrpc.StatementServiceImplBase {

    // Server streaming: one request, many responses
    @Override
    public void getStatement(
            StatementRequest request,
            StreamObserver<Transaction> observer) {

        String accountId = request.getAccountId();
        // Stream transactions one by one over HTTP/2
        for (int i = 0; i < 100; i++) {
            observer.onNext(Transaction.newBuilder()
                    .setId("TXN-" + i)
                    .setAmount(new BigDecimal("1500.00")
                            .toPlainString())
                    .setDescription("EMI Payment")
                    .build());
        }
        observer.onCompleted();
        // Status sent in trailers AFTER all data
    }
}

Why does gRPC need binary framing?

HTTP/2 is binary by design, which matches gRPC's binary Protocol Buffers payloads and its length-prefixed message framing. HTTP/1.1 is text-oriented with textual headers, which is less efficient.

DIAGRAM
HTTP/2 Binary Frame:
┌──────────────────────────────────────┐
│  Length (3 bytes)                     │
│  Type: DATA (0x0)                    │
│  Stream ID: 5                        │
│  Payload: [5-byte gRPC header]       │
│           [compressed protobuf msg]  │
└──────────────────────────────────────┘

HTTP/1.1 Text:
POST /com.bank.AccountService/Transfer HTTP/1.1\r\n
Content-Type: application/grpc\r\n
... text headers ...

Why does gRPC need trailers?

gRPC communicates the final call status (grpc-status code and message) in HTTP trailing headers sent after the response body. This is essential for streaming because the status is only known after all messages are sent. HTTP/1.1 does not support trailers reliably.

DIAGRAM
HTTP/2 Response:
  HEADERS frame:  content-type: application/grpc
  DATA frame:     [transaction 1]
  DATA frame:     [transaction 2]
  DATA frame:     [transaction 3]
  HEADERS frame:  grpc-status: 0    ← TRAILER
                  grpc-message: OK   ← TRAILER

HTTP/1.1 cannot send headers AFTER the body!

How is HTTP/2 different from HTTP/1.1 for gRPC? (Comparison)

| Feature | HTTP/2 | HTTP/1.1 |
|---|---|---|
| Multiplexing | Many streams over one connection | One request/response per connection |
| Head-of-line blocking | No (at HTTP layer) | Yes (slow response blocks others) |
| Streaming | Full-duplex bidirectional | Request then response only |
| Framing | Binary frames | Text-based |
| Header compression | HPACK | None |
| Trailers | Supported | Not reliably |
| Connection reuse | Inherent (one connection) | Connection pooling needed |

What breaks when HTTP/2 is not preserved end to end?

An HTTP/1.1-only proxy or an incorrectly terminating load balancer silently breaks gRPC multiplexing and streaming. You must verify HTTP/2 is preserved on every hop between gRPC peers.

DIAGRAM
┌──────────┐     HTTP/2     ┌──────────┐     HTTP/1.1!    ┌──────────┐
│  Client  │───────────────→│  Proxy   │────────────────→│  Server  │
│          │  multiplexed   │ (breaks  │  one req at a   │          │
│          │  streams       │  HTTP/2) │  time           │          │
└──────────┘                └──────────┘                  └──────────┘

Result: multiplexing lost, streaming broken, trailers lost

Why can browsers not speak native gRPC?

Browsers do not expose raw HTTP/2 framing to JavaScript. They use the fetch API and XMLHttpRequest, which do not give access to HTTP/2 streams, trailers, or binary framing directly. This forces the use of gRPC-Web with a translating proxy like Envoy.

DIAGRAM
Browser ──gRPC-Web (HTTP/1.1 or HTTP/2)──→ Envoy Proxy ──native gRPC──→ Server
                                             │
                                    Translates between
                                    gRPC-Web and gRPC

What about HPACK header compression?

HTTP/2's HPACK compression reduces overhead for the many small metadata headers gRPC sends per call (content-type, grpc-encoding, authority, etc.). HTTP/1.1 sends headers as uncompressed text on every request.

What should a senior engineer know?

Always verify HTTP/2 is preserved on every hop between gRPC peers. An older HTTP/1.1-only proxy or an incorrectly terminating load balancer will silently break multiplexing and streaming. The HTTP/2 dependency is also why gRPC-Web exists and why some older infrastructure requires careful configuration to support gRPC.

Visual Overview

DIAGRAM
┌───────────────────────────────────────────────────┐
│      HTTP/2 Features gRPC Depends On              │
├───────────────────────────────────────────────────┤
│                                                   │
│  ┌──────────────────────────────┐                 │
│  │  Stream Multiplexing         │                 │
│  │  Stream 1: Transfer call     │                 │
│  │  Stream 3: Balance call      │  ONE TCP conn   │
│  │  Stream 5: Statement stream  │                 │
│  │  Stream 7: Fraud check       │                 │
│  └──────────────────────────────┘                 │
│                                                   │
│  ┌──────────────────────────────┐                 │
│  │  Bidirectional Streaming     │                 │
│  │  Client → DATA DATA DATA     │                 │
│  │  Server → DATA DATA DATA     │  same stream    │
│  │  Server → TRAILERS (status)  │                 │
│  └──────────────────────────────┘                 │
│                                                   │
│  ┌──────────────────────────────┐                 │
│  │  Binary Framing              │                 │
│  │  [length][type][stream-id]   │                 │
│  │  [protobuf payload]          │  compact        │
│  └──────────────────────────────┘                 │
│                                                   │
│  HTTP/1.1 lacks ALL of these:                     │
│  - No multiplexing (one req at a time)            │
│  - No bidirectional streaming                     │
│  - Text-based headers (no HPACK)                  │
│  - No reliable trailers                           │
└───────────────────────────────────────────────────┘

Key Takeaway

gRPC relies on HTTP/2 because its core features map directly onto HTTP/2 capabilities that HTTP/1.1 does not have. HTTP/2 gives stream multiplexing, so many independent RPCs run concurrently over one connection without blocking each other. It gives full-duplex bidirectional streaming, so a single logical call can carry a sequence of messages in both directions. It is binary by design, matching gRPC's Protocol Buffers and length-prefixed framing. And it supports trailers, which gRPC uses to send the final status code after a streamed body.

On HTTP/1.1, several things break. There is no real multiplexing, so a connection handles one request and response at a time, defeating gRPC's concurrent-calls model. There is no true full-duplex bidirectional streaming, so client-streaming and bidirectional calls cannot be represented. There are no reliable trailers, so the status-after-stream mechanism fails. And the text-oriented framing is mismatched with gRPC's binary payloads.

In banking work at National Bank of India a server-streaming statement feed used one request for Rajesh's account to yield a continuous stream of transaction entries on a single call, with the final status delivered in trailers. That pattern only exists because of HTTP/2 streaming and trailers. At the same time the transfer service fires many concurrent account calls over one multiplexed channel without them blocking each other.

The HTTP/2 dependency is exactly why browsers cannot speak native gRPC, since they do not expose raw HTTP/2 framing to JavaScript, so gRPC-Web with a translating proxy like Envoy is required. It is also why HTTP/2 must be verified on every hop, because an older HTTP/1.1-only proxy or an incorrectly terminating load balancer silently breaks multiplexing and streaming.

Remember one sentence: gRPC needs HTTP/2's multiplexing, bidirectional streaming, binary framing, and trailers, and HTTP/1.1 lacks every one of them, so gRPC's concurrency and streaming model cannot run on it.

---

Share
Use ← → arrow keys to navigate