gRPC Mechanics#
gRPC is an RPC framework that uses HTTP/2 as transport and Protocol Buffers as the wire format. You write .proto files; tooling generates client and server stubs in many languages.
flowchart LR
Proto[.proto file<br/>service + messages] -->|protoc| ClientStub[Generated client]
Proto -->|protoc| ServerStub[Generated server]
Client[App code] --> ClientStub
ClientStub -->|HTTP/2 + protobuf| ServerStub
ServerStub --> Server[App handler]
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
class Client,Server service;
class ClientStub,ServerStub edge;
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
Four call types: unary (one req, one resp), server-streaming, client-streaming, bidirectional streaming. The streaming flavours leverage HTTP/2 streams natively.
gRPC turns the network into a typed function-call boundary. The combination of HTTP/2 multiplexing + protobuf efficiency makes it the default for high-throughput service-to-service traffic.
The wire format#
syntax = "proto3";
package payments.v1;
service PaymentService {
rpc Charge (ChargeRequest) returns (ChargeResponse);
rpc StreamTransactions (TxFilter) returns (stream Transaction);
rpc UploadEvents (stream Event) returns (UploadAck);
rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}
message ChargeRequest {
string customer_id = 1;
int64 amount_cents = 2;
string currency = 3;
}
protoc generates client/server code in 10+ languages. Wire format is compact binary; fields are identified by tag number, so renaming is safe.
Four call types#
flowchart TB
subgraph Unary
C1[Client] -->|req| S1[Server]
S1 -->|resp| C1
end
subgraph SS[Server streaming]
C2[Client] -->|req| S2[Server]
S2 -->|resp1| C2
S2 -->|resp2| C2
S2 -->|...| C2
end
subgraph CS[Client streaming]
C3[Client] -->|req1| S3[Server]
C3 -->|req2| S3
S3 -->|resp| C3
end
subgraph Bidi
C4[Client] -->|req1| S4[Server]
S4 -->|resp1| C4
C4 -->|req2| S4
S4 -->|resp2| C4
end
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
Server streaming: log tailing, paginated feed without round trips. Client streaming: uploads with progressive validation. Bidirectional: chat, real-time market data.
HTTP/2 mapping#
| gRPC | HTTP/2 |
|---|---|
| Method | :path = /payments.v1.PaymentService/Charge |
| Headers | Initial HEADERS frame |
| Request body | DATA frames |
| Trailers (status) | Final HEADERS frame (grpc-status, grpc-message) |
| Cancellation | RST_STREAM |
| Streaming | Multiple DATA frames before close |
Trailers are gRPC's clever trick: HTTP status is always 200; the real outcome is in trailing headers, so streaming errors after partial data are representable.
Error model#
grpc-status: 0 OK
3 INVALID_ARGUMENT
4 DEADLINE_EXCEEDED
5 NOT_FOUND
7 PERMISSION_DENIED
8 RESOURCE_EXHAUSTED
13 INTERNAL
14 UNAVAILABLE
Plus grpc-message (human-readable) and optional google.rpc.Status details for structured error payloads.
Deadlines and cancellation#
# client
stub.Charge(req, timeout=2.0)
# server
def Charge(self, req, ctx):
if ctx.time_remaining() < 0.1:
ctx.abort(grpc.StatusCode.DEADLINE_EXCEEDED, "no time")
Deadlines propagate through chained RPCs; if upstream gave you 500ms and you've spent 200ms, your downstream RPCs see 300ms. Critical for tail-latency control.
Interceptors (middleware)#
class AuthInterceptor(grpc.ServerInterceptor):
def intercept_service(self, continuation, handler_call_details):
if not valid_token(handler_call_details.invocation_metadata):
...
return continuation(handler_call_details)
Used for auth, logging, tracing, retries, rate limiting. Same shape as HTTP middleware.
Load balancing#
flowchart TB
C[Client] --> Resolver
Resolver --> List[Backend list]
C --> LB[gRPC-LB policy<br/>pick_first / round_robin / xDS]
LB --> B1[Backend 1]
LB --> B2[Backend 2]
LB --> B3[Backend 3]
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
gRPC clients are smart: they connect to multiple backends directly and pick per-RPC, sidestepping the sticky-connection problem of L4 LB + HTTP/2. Policies:
- pick_first: connect to first available; simple.
- round_robin: spread across all healthy backends.
- xDS / Envoy: Istio-style dynamic config.
For mesh, sidecars handle this. For direct LB, use headless services (Kubernetes), DNS SRV records, or a service registry.
Retries#
gRPC supports retries declaratively in the service config:
{
"methodConfig": [{
"name": [{"service": "payments.v1.PaymentService"}],
"retryPolicy": {
"maxAttempts": 3,
"initialBackoff": "0.1s",
"maxBackoff": "1s",
"backoffMultiplier": 2.0,
"retryableStatusCodes": ["UNAVAILABLE"]
}
}]
}
Only retry idempotent calls (annotate or test). Combine with deadlines; budget shouldn't be consumed by retries past the deadline.
When to choose gRPC#
- Internal service-to-service.
- High throughput, low latency.
- Polyglot stack with shared schema.
- Streaming endpoints natural to the domain.
When to skip gRPC#
- Public-facing APIs (REST/GraphQL is more browser-friendly).
- Web clients (grpc-web is OK but limited).
- Simple CRUD endpoints (REST is fine and faster to debug).
Where gRPC connects#
flowchart TB
GR((gRPC))
H2[HTTP/2 deep dive<br/>required transport]
HTTP[HTTP protocols<br/>compared with REST]
REST[REST API design<br/>alternative style]
GW[API Gateway<br/>REST↔gRPC translator]
H2 --> GR
HTTP -. compared with .-> GR
REST -. alternative .- GR
GR --> GW
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class GR service;
class H2,HTTP,REST,GW datastore;
Glossary & fundamentals#
| Tag | Concept | What it is | Page |
|---|---|---|---|
HLD |
HTTP2 deep dive | the transport | http2-deep-dive |
HLD |
HTTP protocols | comparison overview | http-protocols |
HLD |
API Gateway | gRPC behind an API gateway | api-gateway |
LLD |
REST API design | the major alternative | rest-api-design |
Quick reference#
Transport#
HTTP/2 + protobuf binary.
Call types#
| Type | Use |
|---|---|
| Unary | Default RPC |
| Server-stream | Tail logs, paginated feeds |
| Client-stream | Resumable uploads |
| Bidi-stream | Chat, market data |
HTTP/2 mapping#
:path=/<package>.<service>/<method>- Body: protobuf in DATA frames
- Status: trailers (HTTP 200 always)
- Cancel: RST_STREAM
Status codes#
0 OK · 3 INVALID_ARGUMENT · 4 DEADLINE_EXCEEDED · 5 NOT_FOUND · 7 PERMISSION_DENIED · 8 RESOURCE_EXHAUSTED · 13 INTERNAL · 14 UNAVAILABLE
Deadlines#
Propagate through chains; subtract elapsed time.
Interceptors#
Auth, logging, tracing, retries, rate limit.
LB policies#
pick_first, round_robin, xDS. Clients balance per-RPC, not per-connection.
Retries#
Service config JSON; retry only idempotent calls; budget must fit in deadline.
When to use#
- Internal service-to-service
- Polyglot stacks
- Streaming workloads
- High throughput
When to skip#
- Browsers (use grpc-web with caveats)
- Public APIs
- Simple CRUD
Refs#
- grpc.io docs
- protobuf.dev
- gRPC over HTTP/2 spec
FAQ#
What is gRPC?#
gRPC is an RPC framework using HTTP/2 as transport and Protocol Buffers as the wire format. You define services in .proto files and generate clients and servers in many languages.
What is the difference between gRPC and REST?#
gRPC uses binary protobuf over HTTP/2 with code-generated stubs and typed contracts. REST uses JSON over HTTP/1.1 or HTTP/2 and is human-readable but less efficient.
What are the four call types in gRPC?#
Unary (one request, one response), server-streaming, client-streaming, and bidirectional streaming. Streaming flavours ride directly on HTTP/2 streams.
When should I choose gRPC over REST?#
Pick gRPC for high-throughput service-to-service traffic, strong typing, and streaming. Stick with REST for browser-facing APIs or simple integrations with many clients.
Does gRPC work in the browser?#
Browsers cannot speak raw HTTP/2 gRPC. Use gRPC-Web with a proxy like Envoy that translates between browser-friendly HTTP and native gRPC.
Related Topics#
- HTTP/2 Deep Dive: the transport gRPC requires
- REST API Design: the alternative interface style
- API Gateway: where REST clients meet gRPC backends
Further reading#
- Doc - gRPC official documentation
- Doc - Protocol Buffers - Language Guide
- Blog - Google Cloud - gRPC vs REST
- Spec - gRPC over HTTP/2