Back to the map

Module 03 · Load balancing · Lesson 3 of 5

Health checks and failover

A balancer is only as good as its definition of healthy. Liveness versus readiness, shallow versus deep checks, thresholds that avoid flapping, draining on deploy, and how the same ideas govern failover at the database and region level.

CoreMust-knowMid 11 minVideo Updated Nov 2026
Video walkthrough · 2:32 · narrated, with captions

Why it matters

Redundancy without detection is decoration. Two servers behind a balancer that cannot tell one has died will send half of all traffic into a hole. Health checks are the detection, failover is the response, and the details (what the check tests, how often, how many failures it takes) decide whether an incident lasts five seconds or until a human notices. The same mechanics, scaled up, are how a database replica becomes primary and how traffic leaves a failed region.

The idea

A health check is a probe the balancer (or orchestrator) sends to each backend. Pass and the backend receives traffic; fail enough times in a row and it is drained: removed from rotation until it passes again. Two distinctions do most of the work.

Liveness versus readiness. Liveness asks "is this process alive at all?" and a failure means restart it. Readiness asks "can this instance serve traffic right now?" and a failure means stop routing to it but leave it running: it may be warming a cache, waiting on a dependency or shutting down gracefully. Conflating them causes restart loops during a dependency outage, which turns a slow service into a dead one.

Shallow versus deep. A shallow check returns 200 if the process responds. A deep check also verifies dependencies: the database connection, the cache, the downstream service. Deep checks catch more, and they create a trap: if every instance's deep check fails because one shared dependency is down, the balancer drains the entire pool and a partial outage becomes a total one. The rule is that a readiness check should test what this instance needs to serve degraded-but-useful responses, not everything it ever calls.

Balancerprobe every 5 sGET /healthzGET /healthzInstance A200, 200, 200Instance B503, 503, 5033 fails → drainOut of rotationuntil 2 passes
Checks run on an interval; a backend is drained after N consecutive failures and restored after M consecutive passes. Thresholds prevent flapping.

Tuning the numbers

Interval, timeout, unhealthy threshold and healthy threshold together set detection time and stability. A 5-second interval with a 3-failure threshold detects a dead instance in about 15 seconds; a 2-second interval with 2 failures detects in 4 but is more sensitive to a single slow response. Make the healthy threshold at least as strict as the unhealthy one so an instance does not flap in and out of rotation under marginal conditions.

Deploys and graceful shutdown

Most "random 502s during deploy" come from killing an instance while requests are in flight. The sequence that avoids it: the instance fails its readiness check first (or the orchestrator removes it from the pool), the balancer stops sending new requests, in-flight requests finish (connection draining, typically 10 to 30 seconds), then the process exits. Readiness failing before shutdown is what makes zero-downtime deploys work.

The same pattern at larger scale

LevelWhat is checkedWhat fails overTypical time
InstanceHTTP readiness endpointBalancer drains the instanceSeconds
DependencyClient-side timeouts and error ratesCircuit breaker opens; callers degradeSeconds
DatabaseReplication heartbeat, primary reachabilityA replica is promoted; writers reconnectTens of seconds; risk of split brain
RegionSynthetic probes from outsideDNS or anycast routes traffic elsewhereMinutes, bounded by TTL
Detection gets slower and the blast radius larger as you go down the table, which is why instance-level checks matter most.

Trade-offs

Fast detection means low thresholds, which means more false positives and flapping; slow detection means longer partial outages. Deep checks find more problems and can turn one dependency failure into a full drain. Automatic database failover removes humans from the critical path and introduces split-brain risk if the old primary was only partitioned, not dead. Every one of these is a dial, and the right setting depends on how expensive a false failover is compared with a late one.

In an interview

Make the check concrete: "Readiness at /healthz every five seconds, three failures to drain, two passes to restore; it checks the database connection pool but not downstream services, so a payments outage degrades checkout rather than draining the whole API." Then mention deploys: "Instances fail readiness and drain for twenty seconds before exit." And for the database: "Automatic promotion of a replica, with fencing so the old primary cannot accept writes." That covers detection, response and the classic trap.

Check yourself

Every API instance's health check verifies the database, the cache and the recommendations service. The recommendations service goes down. What happens to the API?

Health checks and failover · Backplane