gRPC in Microservices & Load Balancing
🌐 gRPC in Microservices & Load Balancing
Service Discovery
In a real microservices deployment, a service like order-service rarely runs as one fixed instance — it runs as many, scaling up and down, restarting, and being redeployed constantly. A client needs a way to find currently healthy instances rather than hardcoding one IP address that might not even exist anymore by the time a call is made. Service discovery solves this — a DNS record resolving to multiple IPs, or a dedicated registry (Consul, etcd, or Kubernetes' own built-in service discovery) that gRPC's resolver plugins can query directly.
Client-Side Load Balancing
With client-side load balancing, the gRPC client itself receives a list of available addresses (via service discovery) and decides which one to send each call to — round-robin is the simple default. This works especially well for gRPC specifically because of Chapter 1's HTTP/2 multiplexing: a client picks a backend connection once and reuses it for many calls, rather than a fresh choice being needed for every individual request the way a simpler, connectionless client model might behave.
Proxy Load Balancing
The alternative: a dedicated proxy (an L7 proxy like Envoy, common in a service mesh) sits between client and servers. The client just talks to the proxy — it never needs to know about individual instances, service discovery, or balancing logic at all; the proxy handles all of it.
Client-Side vs. Proxy Load Balancing
Client-Side
The client is balancing-aware — it runs resolver logic and picks a backend itself. Simpler infrastructure, more logic embedded in every client.
Proxy
The client stays simple — a proxy (often part of a service mesh like Istio+Envoy) does all the routing and balancing work centrally.
| Approach | Who Decides Routing | Common Use |
|---|---|---|
| Client-side LB | The client itself, via a resolver | Simpler deployments, fewer moving infrastructure pieces |
| Proxy LB | A dedicated proxy/service mesh | Larger microservice fleets, centralized traffic policy |
Client-Side LB Fits When
The deployment is simpler, and adding resolver/balancing logic to clients directly is an acceptable trade for not running extra infrastructure.
Proxy/Service Mesh Fits When
Many services need consistent routing, retry, and observability policy applied centrally, without embedding that logic separately into every client.
When gRPC Is the Right Internal-Service Choice vs. REST/GraphQL for Public APIs
This closes the loop back to Chapter 1's positioning: gRPC's performance and schema-first benefits pay off most within a trust boundary you control — internal services, secured with mTLS (Chapter 7), discovered and balanced across instances (this chapter). The moment an API needs to be called by a browser or an arbitrary third-party developer, Chapter 1's browser-support gotcha becomes decisive again: REST or GraphQL's universal compatibility wins for anything public-facing, while gRPC remains the stronger choice for the internal service-to-service traffic it was originally built for.
💻 Coding Challenges
Challenge 1: Explain Why Hardcoding an IP Fails
Explain why a gRPC client hardcoding one server IP address is a poor fit for a real microservices deployment, using this chapter's material.
Goal: Practice connecting the dynamic nature of scaled deployments to the need for service discovery.
Challenge 2: Client-Side or Proxy LB?
A small team runs three internal services with simple routing needs and wants to avoid operating extra infrastructure. A larger organization runs 200 microservices and wants centralized traffic policy and observability. Recommend an approach for each.
Goal: Practice matching organizational scale to the right load-balancing approach.
Challenge 3: Synthesize the Course's gRPC-vs-REST Thread
Using material from Chapters 1, 7, and this chapter, explain in a few sentences why gRPC is well suited to internal microservices but not to a public API a mobile app calls directly.
Goal: Practice pulling together multiple chapters' worth of reasoning into one coherent argument.
Chapter 1's HTTP/2 multiplexing is a real strength — but it has an operational cost here: because gRPC clients reuse one long-lived connection for many calls, a client that already picked a backend connection before a new instance was added to the pool has no reason to reconnect and discover it. In a naive setup, a freshly scaled-up instance can sit there receiving zero traffic while existing clients keep happily reusing their old connections to the original instances — the opposite of what adding capacity was supposed to achieve. Real deployments address this with periodic connection refresh/rebalancing (client-side) or by routing all traffic through a proxy (this chapter's proxy approach) that's aware of new instances immediately, rather than assuming clients will naturally redistribute themselves.
🎯 What's Next
The final chapter is the Capstone: Building a Small gRPC Service — a real two-service example (a user service plus an order service calling it) combining schema design, streaming, interceptors, and auth.