Architecture patterns
Resilience patterns
The toolkit for keeping one failure from becoming an outage, from timeouts and retries to circuit breakers, bulkheads, load shedding and cells. Start here for the resilience map.
Large outages rarely start large. They start with one slow disk, one overloaded cache node, or one dependency whose latency drifts from 50 ms to 5 seconds. What turns that into a site-wide outage is the rest of the system's reaction. Callers wait too long, retry too eagerly, queue too much, and keep sending traffic to something that cannot serve it.
Resilience patterns are the deliberate choices that keep a failure small. Each one keeps a problem inside one dependency, one feature, one cell or one customer.
Why failures spread
A slow dependency is more dangerous than a dead one. A dead dependency fails fast, and your code handles that. A slow one holds your threads, connections and queue slots while it works through its backlog. Your callers then hold theirs, and the failure climbs the call graph. Cascading failures walks through the mechanism with numbers.
Concepts in this topic
Read them in order. Each one builds on the last.
| Step | Concept | What it answers |
|---|---|---|
| 1 | Cascading failures | How does one slow dependency take down everything? |
| 2 | Timeouts and deadlines | How long should a call wait, and how does a whole request stay in budget? |
| 3 | Retry budgets and hedging | When is a retry safe, and how many are too many? |
| 4 | Circuit breakers | How do you stop calling something that is almost certain to fail? |
| 5 | Bulkheads and isolation | How do you keep one dependency from consuming every resource? |
| 6 | Load shedding and degradation | What do you drop when demand exceeds capacity? |
| 7 | Limiting blast radius | How does the architecture shrink the damage of any failure? |
Backpressure, which is how a slow consumer tells a fast producer to slow down, is covered in backpressure. The rule that applies everywhere: every queue needs a bound and a policy for what happens at the bound.
Testing resilience
A mechanism that has never fired is a hypothesis. Fault injection turns it into evidence.
- In tests. Tools such as Toxiproxy sit between your service and a dependency, adding latency, dropping connections or limiting bandwidth. Check that timeouts fire, breakers open and fallbacks render.
- In production. Netflix's Chaos Monkey (2011) randomly ended production instances during business hours, which forced teams to build services that survive instance loss. Managed tools such as AWS Fault Injection Service and Gremlin run controlled experiments with stop conditions.
- Game days. A scheduled exercise where a team breaks something on purpose, such as a failed database or a dead zone, and watches whether alerts, runbooks and automation work. These often reveal a broken alert channel or a deleted runbook script.
Start small: one dependency, in staging, with a clear hypothesis. For example: "If pricing returns errors, product pages render without prices, and the error rate stays under 1%." The incident response and disaster recovery pages cover the human side.
Common mistakes
- Assuming a slow dependency is harmless. Slowness consumes your threads just as errors do.
- Adding a fallback that is never tested. It will run for the first time during an emergency.
- Retrying at every layer. Multiple layers of retries multiply load on the failing dependency.
- Leaving queues unbounded. An unbounded queue hides overload and turns it into long waits.
Key takeaways
- Cascades start with slowness. Retries and inefficiency under load finish the job.
- Every call gets a timeout, and every request carries a deadline that downstream calls respect.
- Circuit breakers stop calls to a failing dependency. Bulkheads cap how much capacity any one dependency can use.
- Shed load early and by priority, so accepted work still meets its deadline.
- Limit blast radius through architecture, with cells and static stability, before anything fails.
- Prove resilience with fault injection and game days.
Further learning
Netflix engineers explain how prioritized load shedding in their API gateway keeps playback working during spikes:
Peter Vosshall's re:Invent talk is the clearest explanation of how AWS uses regions, zones, cells and shuffle sharding to limit blast radius:
Start with cascading failures to see the mechanism behind the rest of this topic.
Related
Cascading failures
How one slow dependency exhausts threads, then turns into a full outage through retries and overload, with the arithmetic that shows why.
Circuit breakers
A circuit breaker watches a dependency's recent failures, trips to fail fast when the failure rate is high, and probes again after a cool-down.
Limiting blast radius
Architecture that keeps a failure small by construction, using static stability, cells and shuffle sharding, with the arithmetic behind each.
What goes wrong in distributed systems
Partial failure, unreliable networks, paused processes and timeouts, and the fencing tokens and failure detectors that let you build correct systems on top of them.
Idempotency and retries
Making operations safe to retry, with idempotency keys, deduplicating consumers and jittered backoff, so at-least-once delivery never means a double charge.