Skip to main content

Service Discovery & Client vs Server-Side Load Balancing

Level 4: Level 4: Scaling Compute & Trafficmedium30 minservice-discoveryload-balancingmicroservices

A registry (heartbeats or k8s readiness-driven Endpoints) keeps healthy addresses current within seconds; choose server-side simplicity or client-side/mesh locality deliberately.

Callers must learn addresses that change every minute

In a fleet that autoscales and redeploys constantly, a service's instances come and go every minute: IPs and ports change, instances are added under load and terminated on scale-in. So a caller cannot hardcode addresses, and it cannot rely on long-TTL DNS, because the moment an instance is terminated a stale address keeps receiving traffic and callers get connection errors. Service discovery lets a caller learn the current set of healthy addresses, and the second question is who makes the balancing decision: a central load balancer, or each client.

Check yourself
You publish instance IPs in DNS with a 60 second TTL and call it service discovery. An instance is terminated during scale-in. Where does its traffic go for the next minute?

The service registry

  • Self-registration: each instance registers itself on startup and sends periodic heartbeats (Consul, etcd, Netflix Eureka). If heartbeats stop, the registry marks it gone. On graceful shutdown it deregisters.
  • Platform-managed: the orchestrator maintains it for you. In Kubernetes, a Service is a stable name/VIP, and the control plane keeps its Endpoints / EndpointSlices in sync with the pods that pass their readiness probe.

Health-based removal keeps discovery honest. The registry advertises only instances that pass active health checks or are heartbeating, combined with readiness so a new instance receives traffic only once warm. The number that matters is propagation speed: how fast a terminated or failing instance actually leaves every caller's view. With short check intervals plus fast registry watch/push, a bad instance is out of rotation within seconds; with long DNS TTLs it can be minutes, which is the failure mode to avoid.

Where the balancing decision happens

  • Server-side load balancing: clients hit one stable VIP or DNS name and a dedicated load balancer (ALB/NLB, Envoy, Nginx) picks a backend. Clients stay dumb and simple, and control is central. The cost is an extra network hop and a component you must scale and keep HA.
  • Client-side load balancing: the client fetches the healthy instance list from the registry (or a mesh sidecar) and picks a backend itself (gRPC client-side LB, a sidecar Envoy). This removes the extra hop and enables smart, locality-aware policies (prefer same-zone, least-request with local load view). The cost is complexity pushed into every client and a hard dependency on fast registry propagation.

A service mesh (Istio or Linkerd, Envoy sidecars) is the popular middle ground: client-side benefits (no central-LB hop, locality, per-request balancing, retries, mTLS) with central configuration. The price is real operational complexity (a control plane and a sidecar per pod).

Check yourself

Sort each property by where the balancing decision lives.

Clients stay dumb and hit one stable VIP
Every request pays an extra network hop
Prefer-same-zone and least-request decisions made with a local load view
Balancing complexity is pushed into every caller
One central choke point that can become the bottleneck
A hard dependency on fast registry propagation

Interview nuance: the discriminator is where you want complexity to live. Central LB = simple clients, extra hop, one scaling choke point. Client-side/mesh = no hop and smart routing, but complexity and propagation risk in every caller. A strong concrete answer: Kubernetes with a mesh for a polyglot fleet, or gRPC client-side LB backed by etcd for a gRPC-heavy one, with short health-check intervals so bad instances leave rotation within seconds.

  registry (Consul/etcd/Eureka  |  k8s Endpoints via readiness)
       ^ register/heartbeat            ^ controller keeps in sync
  server-side:  client -> [ VIP/LB ] -> backend        (1 extra hop, central control)
  client-side:  client (has list) ---> backend         (no hop, smart local policy)

Recap: callers learn healthy addresses from a service registry (self-registration with heartbeats, or Kubernetes Endpoints tied to readiness), unhealthy instances leave rotation in seconds; server-side LB keeps clients simple at the cost of a hop and a central component, client-side/mesh removes the hop and adds locality at the cost of per-client complexity, and the classic wrong turn is hardcoded IPs or long-TTL DNS that keeps sending traffic to terminated instances.

Check yourself
You are designing discovery for an autoscaling gRPC fleet whose instance set changes every minute. Which shape keeps a dead instance's lingering traffic to seconds?

Apply

Your turn

The task this lesson builds to.

Design service discovery for a microservice fleet that autoscales and redeploys constantly, and choose between client-side and server-side load balancing, justifying how unhealthy instances get removed.

Think about

  1. When instances come and go every minute, how does a caller learn the current set of healthy addresses?
  2. Who makes the load-balancing decision: a central load balancer, or each client with a local view?
  3. How fast does an unhealthy or terminated instance get pulled out of rotation?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design service discovery and load balancing for a Netflix-scale fleet of thousands of instances across three AWS regions and multiple availability zones, where deploys and autoscaling churn instances continuously, cross-AZ traffic is a real cost line, and a single instance failure must be invisible within seconds. Justify client-side vs server-side.

Think about

  1. What can a zone-aware client do that a central LB cannot express as cheaply?
  2. Why does client-side passive detection beat waiting for a registry update?
  3. Why per-region registries rather than one global one?