Circuit Breakers, Retries & Bulkheads
You'll learn to
- -Explain how one slow dependency can bring down a chain of healthy services, with numbers
- -Explain the three states of a circuit breaker and trace one through a failure and recovery
- -Explain retries with exponential backoff and jitter, and when not to retry
- -Explain bulkheads, and how timeouts, breakers, retries and bulkheads work together
In a system of many services, the most dangerous failure is not a crash. A crashed service is detected quickly and routed around. The dangerous one is a service that is merely slow, because callers keep waiting for it, and the waiting spreads. This chapter explains how a failure spreads, and the three standard defenses: circuit breakers, retries done properly, and bulkheads.
Cascading Failure, in Numbers
Service A calls Service B, which calls Service C. Say B has 100 threads, normally a call to C takes 50 milliseconds, and requests reach B at 200 per second. Now C becomes slow, and each call hangs for 10 seconds until it times out. Each request now ties up a B thread for 10 seconds, so B would need 200 x 10 = 2,000 threads to keep up and has only 100. At 200 requests a second the 100 threads are all taken within 100 / 200 = half a second. B can now answer nothing, even requests that do not touch C, and A, waiting on B, runs out of threads next. One slow dependency took down the whole chain within seconds.
An Analogy: The Fuse Box
A house has a circuit breaker in its fuse box. If something draws too much current, the breaker trips and cuts that circuit, so the wiring does not overheat and burn the house down. After the fault is fixed, you flip it back. The house sacrifices one circuit to save the whole.
- -The overloaded appliance is the struggling dependency.
- -The breaker tripping is the circuit breaker opening: calls fail fast instead of piling up.
- -Flipping the breaker back on after the fix is the breaker closing again.
Circuit Breakers
The diagram shows the breaker between a caller and a struggling dependency:
A circuit breaker sits between a caller and a struggling dependency, failing fast instead of letting requests pile up.
A circuit breaker watches calls to a dependency and has three states. Closed is normal: calls pass through, and failures are counted. Open means failures crossed a threshold, say half of the last 20 calls failed, so the breaker stops sending calls and answers at once with a fallback such as a cached value, a default, or a clear error. Half-open comes after a cooldown, say 30 seconds: the breaker lets one trial request through. If it succeeds, the breaker closes and traffic resumes; if it fails, the breaker opens again for another cooldown. In the example above, an open breaker would have answered in about a millisecond instead of ten seconds, and B would never have run out of threads. The card below describes the component as it appears in the lab:
Think of a circuit breaker in your house's electrical panel. When too much electricity flows through a wire (a short circuit), the breaker TRIPS and cuts the power. Preventing a fire. A software circuit breaker does the exact same thing for service-to-service calls. Suppose your Order Service calls the Payment Service, and the Payment Service starts timing out (it's overloaded). Without a circuit breaker, the Order Service sends request after request, each one waiting 30 seconds before timing out. Soon, the Order Service itself is stuck with hundreds of pending requests, its thread pool is exhausted, and it crashes too. That's a cascade failure. One sick service takes down the entire system like dominoes. A circuit breaker monitors the failure rate. Once it exceeds a threshold (say, 50% of calls fail), the breaker 'OPENS' and immediately returns an error (or a fallback response like 'Payment currently unavailable, please try again in 60 seconds') WITHOUT even calling the Payment Service. This protects both the caller (Order Service doesn't waste resources) and the failing service (Payment Service gets breathing room to recover). After a cooldown period, the breaker allows a few test requests through ('half-open state'). If those succeed, the breaker closes and normal traffic resumes.
Examples: Resilience4j (Java/Kotlin, the modern standard), Hystrix (Netflix, pioneered the pattern, now in maintenance mode), Polly (.NET), Sentinel (Alibaba), Envoy proxy (built-in outlier detection acts as a circuit breaker), AWS App Mesh
Retries, Done Properly
A retry can rescue a request that failed for a momentary reason, but done carelessly it makes things worse. If a service is struggling and every client retries immediately, the service receives its normal load plus a wave of retries, and may never recover. This is a retry storm. The remedy is exponential backoff with jitter: wait longer after each failure (for example 1 second, then 2, then 4), and add a random amount to each wait so that thousands of clients do not all come back at the same instant.
- -Retry only what is safe to repeat, such as reads and idempotent operations, and keep a cap on attempts, commonly three.
- -Always set a timeout. Without one, a hung call never fails, so it is never retried and never frees its thread.
- -Do not retry errors that cannot change, such as a 400 Bad Request. Retry timeouts and 503 responses.
- -Combine retries with a breaker: when the breaker is open, do not retry at all.
Bulkheads
A ship is divided into watertight compartments, so a hole floods one compartment and not the whole hull. The same idea in software: give each dependency its own pool of threads or connections. Say a service has 100 threads, split into 40 for payments, 40 for the catalog and 20 for recommendations. If recommendations become slow, they can use up only their own 20 threads. Payments and the catalog carry on unharmed, and the page shows without recommendations instead of failing.
In one line: a slow dependency is more dangerous than a dead one. Use timeouts so calls end, circuit breakers so you stop calling a struggling service, backoff with jitter so retries do not become a storm, and bulkheads so one failing dependency cannot consume everything.
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.
Discussion0
Join the Discussion
Sign in to leave comments, reply to others, or like insights.
No comments yet. Be the first to start the thread!