Architecture
Reliability & Resilience
Reliability is delivering the promised outcome consistently; resilience is containing failures and recovering well. Architects often design under the assumption that dependencies will eventually fail, then choose patterns, SLOs, and recovery paths that keep the system useful.
What Is Reliability & Resilience?
Reliability is how consistently a system delivers the intended result. Availability is whether the system can be used at all. Durability is whether committed data survives failures. Resilience is the ability to contain faults, degrade safely, and recover. Fault tolerance is the ability to keep operating through a specific fault without full service loss. Recoverability is how quickly and safely the system can restore normal behavior after damage occurs.
In architecture work, teams often treat failure as a design assumption rather than a surprising exception: not because every dependency is constantly broken, but because partial failure, timeouts, bad deploys, slow disks, and regional incidents are realistic enough that the recovery path must be designed up front.
Related but different reliability terms
Visual Story
Dependency failure → retry storm → circuit breaker saves the system
Reliability & Resilience
⤢ Expand for synchronized narration timeline
Without a circuit breaker (Scenes 2–3), a slow dependency cascades into a full outage. With one (Scene 4), the system degrades gracefully and recovers automatically.
Problem It Solves
Why distributed systems need explicit failure isolation
In a distributed system, every service depends on other services, databases, queues, and third-party APIs. When one dependency slows down, it can block threads in the caller, exhaust shared pools, and take down unrelated functionality.
A failure-model-first approach makes the reasoning explicit: define what can fail, the failure mode you expect, the blast radius if it fails, how you detect it, how you recover, and what degraded behavior is still acceptable while recovery is happening.
A database, queue, region, dependency API, deployment, or control plane.
Timeout, throttling, stale replica, partial write, retry storm, bad data, or total outage.
Which users, journeys, teams, or regions lose functionality when it breaks?
SLIs, alerts, synthetic probes, queue lag, timeout rates, or customer-visible symptoms.
Retry, failover, rollback, replay, operator action, or automated repair.
Read-only mode, stale data, queued work, limited features, or deliberate load shedding.
SLI, SLO, and SLA
Reliability targets drive architecture decisions
SLI vs SLO vs SLA
An SLI is the measured indicator: success rate, latency percentile, freshness, recovery time, or another observable signal. An SLO is the target for that indicator: for example, a checkout path might target a much tighter success and latency goal than a nightly analytics export because the user and business impact are different. An SLA is the external commitment, often legal or commercial, that may attach penalties if the promised level is not met.
Good SLOs are chosen from user harm and business impact, not from round numbers that feel impressive. A tighter SLO usually pushes the architecture toward more redundancy, better automation, safer deploy paths, stronger observability, and more operational investment. A looser SLO may justify a simpler design if the blast radius and recovery time are acceptable.
Resilience Patterns
Core patterns for containing failures and recovering safely
For deeper pattern mechanics, see Retry & Backoff, Circuit Breaker, Bulkhead, Load Shedding, and Idempotency. To see how these failures unfold and how to spot them, read the Production Engineering diagnoses for Retry Storm and Cascading Failure.
How Architects Think
Resilience is about acceptable degradation and recoverability
Resilience is not the same as trying to eliminate every failure. It is designing the system so a realistic fault becomes a bounded, observable problem with a recovery path and an acceptable degraded mode.
Chaos engineering and failover drills are valuable because untested recovery is still a guess. If your SLO says checkout must keep working during a dependency outage, the architecture has to fund that promise with redundancy, isolation, automation, and operator practice.
For incident follow-through, continue to Incident & Postmortem Analysis. For deeper partition and operation-level consistency trade-offs, see Distributed Architecture.
Illustrative Scenario
A payment timeout that takes down checkout (constructed for teaching, not a real incident)
Illustrative incident: at 14:32, a payment provider's P99 latency jumped from 120ms to 8s. The checkout service had no timeout on its payment HTTP client. Within 90 seconds, checkout threads were blocked waiting for payment responses — including threads serving users who were not paying yet.
Why it cascaded: the payment and non-payment code paths shared the same thread pool. Once payment requests filled it, no new requests could be served. A non-critical dependency brought down the entire checkout flow.
What a resilient design changes: an explicit timeout bounds waiting, retries use backoff and jitter, and a circuit breaker opens after repeated failures so the service can fail fast. If payment can be retried later, queued work and idempotency keys make that retry safe. Checkout may degrade, but browsing and cart management stay available. The Incident & Postmortem page walks through the same scenario as a timeline and postmortem.
Architectural lesson: the payment provider being slow is a plausible fault model. The outage came from missing isolation and recovery behavior: no timeout, no breaker, shared thread pool, and no graceful path for degradation.
Trade-offs
What reliability patterns cost
Redundancy vs cost
Higher availability targets often cost disproportionately more, but the curve depends on workload, failure model, and operational maturity. Match redundancy to the business impact of downtime rather than pursuing extra nines by default.
Fail fast vs retry
Retrying hides transient blips but, uncontrolled, turns a slow dependency into a self-inflicted DDoS (retry storm). Failing fast with a circuit breaker protects the system but surfaces errors sooner.
Strong consistency vs availability
During a network partition you may reject work to preserve a stronger consistency guarantee or accept work and reconcile later. The right choice depends on which failure mode is more harmful for that operation.
Graceful degradation vs correctness
Serving a stale cache or a cut-down response keeps the system useful under stress, but returns data that may be wrong. Some domains (payments) forbid this; others (feeds) depend on it.
The consistency-versus-availability trade-off during partitions is subtle and can vary by operation, not just by product label. See Distributed Architecture for the precise partition-time reasoning.
What Can Go Wrong
How resilience architectures fail in practice
One slow dependency blocks all threads. No timeout means no upper bound on blast radius.
Clients retry together without backoff or jitter and overwhelm an already struggling service.
One dependency exhausts the shared pool. Unrelated flows are starved even though they are healthy.
Recovery works technically, but each retry can duplicate a charge, email, or order mutation.
Standby path exists on paper but behaves differently under real traffic or stale data.
Service returns 500 instead of a reduced response. Users lose unrelated features because one dependency is down.
When To Use / When Not To Use
Calibrating resilience investment to actual risk
- → Calling external or failure-prone dependencies
- → A component fault could cascade into critical user journeys
- → Operating against meaningful SLOs or contractual SLAs
- → Degraded service is better than total unavailability
- → The system is low-risk and manual recovery is acceptable
- → Simplicity matters more than shaving rare edge-case downtime
- → The team cannot yet operate the extra redundancy safely
- → A graceful fallback would violate correctness requirements
A third-party payment API starts responding slowly (P99: 8 seconds). Your checkout service has no timeout configured. What is the HIGHEST PRIORITY architectural fix?
Design as if important dependencies will eventually fail, then make the failure bounded, visible, and recoverable.
- 1Reliability, availability, durability, resilience, fault tolerance, and recoverability are related but different design concerns.
- 2Choose SLIs and SLOs from user and business impact; the tighter the promise, the more redundancy and automation you usually need.
- 3Bound waiting with timeouts, then use retries with backoff and jitter only where the operation is safe to retry.
- 4Bulkheads, circuit breakers, graceful degradation, and load shedding contain blast radius instead of pretending faults will not happen.
- 5Untested failover is still a guess. Exercise recovery paths before the first real incident.
Key lesson
The dependency being slow is often the trigger, not the architectural failure. The deeper question is whether your design contained the fault and recovered on purpose.