Linkerd doesn’t actually "balance Protobuf traffic" in the way you might think; it balances any gRPC traffic, and Protobuf is just the serialization format gRPC commonly uses.

Here’s Linkerd balancing gRPC requests between two instances of a simple "echo" service, one running on port 7001 and the other on 7002.

# First, start two echo services on different ports
go run echo/server.go --port 7001 &
go run echo/server.go --port 7002 &

# Then, start a Linkerd client that will forward requests to these services
go run echo/client.go --listen-port 8080 --target-ports 7001,7002

Now, if you send requests to localhost:8080, Linkerd will distribute them across the two echo servers. You can see this in action by observing the request counts in Linkerd’s dashboard or by looking at the server logs.

Linkerd’s magic here is its understanding of the gRPC protocol itself, not just raw TCP connections. When you send a gRPC request, it’s not just arbitrary bytes; it’s a structured message with headers, a method name, and a payload. Linkerd can inspect these components.

When a request arrives at a Linkerd proxy configured for gRPC, it first identifies the connection as gRPC. It then parses the request to extract the grpc-method header. Based on the configured load balancing policy (e.g., round-robin, least-loaded), Linkerd selects a backend instance. Crucially, it doesn’t just forward the bytes; it can potentially apply more intelligent routing based on the gRPC method being called.

The core problem Linkerd solves is that standard TCP load balancing is "dumb." It sees a stream of bytes and distributes connections or packets based on IP and port, or simple round-robin. For protocols like HTTP/2 (which gRPC uses) or gRPC, this is inefficient. A single TCP connection can carry many independent requests. Linkerd, by understanding the gRPC protocol, can balance individual requests within a connection, leading to better resource utilization and faster failover.

The exact levers you control are in the Link resource, specifically the strategy and policy fields.

apiVersion: linkerd.io/v1alpha1
kind: Link
metadata:
  name: my-grpc-service
spec:
  service:
    name: grpc-service.default.svc.cluster.local
    port: 50051
  target:
    - name: grpc-service-v1
      port: 7001
    - name: grpc-service-v2
      port: 7002
  strategy: round-robin # or least-loaded, random
  policy:
    request-timeout: 5s
    retry-on:
      - "cancelled"
      - "deadline-exceeded"

Here, strategy: round-robin means Linkerd will send requests sequentially to each backend. least-loaded would send the next request to the backend with the fewest active requests. retry-on tells Linkerd which gRPC status codes should trigger a retry.

What most people miss is that Linkerd’s gRPC awareness extends beyond just routing. It can also terminate TLS per-request if configured, and crucially, it can apply request-level metrics and tracing before the request even hits your application code. This means you get visibility into your gRPC services without instrumenting your application code itself. The proxy handles it all.

The next concept to grok is how Linkerd’s service mirroring enables canary deployments for gRPC services.

Want structured learning?

Take the full Linkerd course →