Markdown Editor

Resilience and Load Shedding Design Template (Retries, Circuit Breakers)

Failure model, deadlines, retries with jitter and budgets, circuit breakers, bulkheads, backpressure, criticality-based shedding, degradation, fault tests

SystemdesignVollständigGoogle SRE book ch. 21-22; Amazon Builders' Libraryresilienceloadsheddingdesignmath

Anleitung: Use it when a service must survive slow or failing dependencies and its own overload without cascading. Fill the dependency inventory and failure model first, then the per-dependency matrix (13) with real numbers. The main pitfall is retrying at every layer without a budget, which multiplies load on a dependency exactly when it is failing.

Vorschau

Resilience Design: [Service name]

Design record for how one service survives slow, failing and overloaded dependencies and its own overload: failure model, timeouts and deadline propagation, retries with exponential backoff and jitter, retry budgets, circuit breakers, bulkheads, backpressure, load shedding and admission control by criticality, graceful degradation, idempotency, health checks, testing with fault injection, metrics and alerts, and a per-dependency resilience matrix. Concepts follow the Google Site Reliability Engineering book (chapters 21 "Handling Overload" and 22 "Addressing Cascading Failures") and the Amazon Builders' Library articles "Timeouts, retries, and backoff with jitter" and "Using load shedding to avoid overload". Replace every [bracketed] value and every row marked Example; numbers are illustrative assumptions.

Document control

FieldValue
Document ID[RES-ORD-001]
Service[Order API]
Version[0.1]
Status[Draft / In review / Approved / Superseded]
Owner[@service-owner]
Reviewers[@sre], [@staff-engineer]
Last updatedYYYY-MM-DD
Classification[Internal]
Service tier[Tier 1 / 2 / 3]
SLO reference[Link to SLO document]
Related[System design], [FMEA], [Chaos experiments], [Runbook]

Approvals

RoleNameDecisionDate
Service owner[@name][Approved / Changes requested]YYYY-MM-DD
SRE lead[@name][Decision]YYYY-MM-DD
Staff / principal engineer[@name][Decision]YYYY-MM-DD
Owners of critical dependencies[@name][Decision]YYYY-MM-DD

Revision history

VersionDateAuthorChange summary
0.1YYYY-MM-DD[@name]First draft
0.2YYYY-MM-DD[@name]Example: Added retry budget after retry storm in incident INC-[nnn]
0.3YYYY-MM-DD[@name]Example: Criticality classes and shedding thresholds from load test
1.0YYYY-MM-DD[@name]Example: Approved

Contents

1. Introduction and scope

1.1 Purpose

[Example: The Order API accepts and tracks customer orders. It depends on inventory, pricing, payment, a recommendation service and a relational database. In the last two quarters it suffered two cascading failures: a slow recommendation service exhausted the request thread pool, and a retry storm against payment tripled payment's load during its own incident. This document defines how the Order API contains those failures.]

1.2 Resilience objectives

IDObjectiveTarget
RO-01Example: Checkout stays available when any non-critical dependency failsCheckout success at or above 99.9% with recommendations down
RO-02Example: Overload degrades gracefully instead of collapsingGoodput at 2 times capacity stays at or above 90% of capacity
RO-03Example: The service never amplifies a dependency incidentRetry traffic at or below 10% of request traffic at all times
RO-04Example: Recovery is automatic after a dependency recoversBack to normal within 2 minutes without manual action
[RO-nn][Objective][Target]

1.3 Out of scope

  • [Example: loss of a full region (see IT Disaster Recovery Plan Template (ops/disaster-recovery-plan))]
  • [Example: data corruption and backup restore]
  • [Example: volumetric network attacks (edge provider)]

2. Service context and dependencies

2.1 Call graph

Solid arrows are synchronous calls on the checkout path; dotted arrows are optional or asynchronous.

2.2 Dependency inventory

IDDependencyTypeCriticality for checkoutNormal p50 / p99 latencyOwner
DEP-01Example: Orders databaseSync, statefulHard (no checkout without it)3 ms / 25 ms[@team]
DEP-02Example: Inventory serviceSyncHard15 ms / 120 ms[@team]
DEP-03Example: Pricing serviceSyncSoft (cached prices acceptable for 10 minutes)10 ms / 80 ms[@team]
DEP-04Example: Payment serviceSyncHard250 ms / 1 500 ms[@team]
DEP-05Example: Recommendation serviceSyncNone (page renders without it)40 ms / 300 ms[@team]
DEP-06Example: Event busAsyncSoft (outbox buffers events)5 ms / 50 ms[@team]
[DEP-nn][Dependency][Sync / Async][Hard / Soft / None][Latency][@team]

3. Failure model

IDFailure modeTypical causeEffect without protection
FMD-01Dependency slow (latency 10 to 100 times normal)Garbage collection, lock contention, overloaded calleeThreads and connections held; our own queue grows; cascade
FMD-02Dependency returns errorsBug, bad deploy, exhausted resourceErrors propagate; retries add load
FMD-03Dependency unreachableNetwork partition, DNS, certificate expiryConnection timeouts; slow failure if timeouts are long
FMD-04Own overloadTraffic spike, retry storm from clients, reduced capacity after a failureLatency rises for everyone; work completes after clients have given up
FMD-05Partial instance failureOne bad host or zoneFraction of requests fail; health checks may not see it
FMD-06Resource exhaustionMemory leak, file descriptors, connection poolGradual degradation then crash
FMD-07Correlated restartCrash loop, simultaneous deployCapacity drop; thundering herd on dependencies at start
[FMD-nn][Mode][Cause][Effect]

A cascading failure, as described in the SRE book chapter "Addressing Cascading Failures", is a failure that grows through positive feedback: overload on some instances shifts traffic to the rest, which then overload in turn. The mechanisms in sections 4 to 10 each break one of those feedback loops. Score each mode for severity and likelihood in Software FMEA Template (IEC 60812) (ops/fmea-software).

4. Timeouts and deadline propagation

4.1 Setting timeouts

  • Set each dependency timeout from its latency distribution at an acceptable false-timeout rate. Example: if a 0.1% false-timeout rate is acceptable, use the p99.9 latency plus a margin.
  • Separate connection timeout (short, Example: 100 ms in the same region) from request timeout.
  • Never leave a library default (often infinite or 30 to 60 s) on a request path.

4.2 Deadline propagation

The edge sets an overall deadline for the request (Example: 2 000 ms for checkout). Each hop receives the remaining time and subtracts its own expected work before calling further:

Tcall=min⁡(Tdep, Tdeadline−telapsed−treserve)T_{call} = \min\left(T_{dep},\ T_{deadline} - t_{elapsed} - t_{reserve}\right)

where TdepT_{dep} is the dependency's own timeout and treservet_{reserve} is the time needed to build the response after the call returns. If TcallT_{call} is below the callee's minimum useful time, fail fast instead of calling. Propagate the deadline in a request header or the RPC framework's deadline field, and make callees drop queued work whose deadline has passed.

4.3 Timeout chain check

HopTimeoutMust be less than
Client to edgeExample: 3 000 ms (mobile app)User patience
Edge to Order API2 000 ms deadlineClient timeout
Order API to payment1 600 ms or remaining deadline, whichever is lowerEdge deadline minus reserve
Payment to provider1 400 msOrder API's payment timeout
Order API to recommendations150 msIts contribution to page latency budget

Rule: an inner timeout must be shorter than the outer one, otherwise the caller gives up while the callee keeps working, and a retry starts a second copy of the same work.

5. Retries, backoff and retry budgets

5.1 Retry policy

RuleValue
Retryable conditionsExample: connection failure, timeout on idempotent calls, 503 with Retry-After, 429 after Retry-After
Never retriedValidation errors (4xx other than 408 and 429), non-idempotent calls without an idempotency key
Attempts per requestExample: at most 3 (1 initial and 2 retries)
Where retries happenAt one layer only, closest to the failing dependency

5.2 Exponential backoff with jitter

With base delay bb, cap cc and retry number nn (starting at 0), full jitter draws the wait uniformly:

dn∼U(0, min⁡(c, b⋅2n))d_n \sim \mathcal{U}\left(0,\ \min\left(c,\ b \cdot 2^{n}\right)\right)

Example: b=100b = 100 ms, c=2c = 2 s. The first retry waits up to 100 ms, the second up to 200 ms, the fifth up to 1 600 ms and later retries are capped at 2 s. Jitter spreads clients that failed at the same moment so their retries do not arrive together. Honour a server's Retry-After when it is larger than the computed delay.

5.3 Retry amplification

If each of dd layers makes up to aa attempts, the deepest dependency can receive

A=adA = a^{d}

times the original load. Example: 3 attempts at each of 3 layers gives 33=273^3 = 27 times the load, exactly when the dependency is already failing. This is why retries happen at one layer and are bounded by a budget.

5.4 Retry budget

A retry budget caps retries as a share of successful or total requests over a sliding window. The SRE book describes a per-client budget of retries below 10% of requests, and the Builders' Library article describes limiting retries locally with a token bucket. With budget ratio ρ\rho the worst-case load on a failing dependency is

Lmax=(1+ρ)×L,ρ=0.1⇒Lmax=1.1 LL_{max} = (1 + \rho) \times L, \qquad \rho = 0.1 \Rightarrow L_{max} = 1.1 \, L
ParameterValue
Budget ratioExample: 10% of requests in a 10 s window, per dependency, per instance
ImplementationExample: token bucket: each request adds 0.1 token, each retry spends 1, bucket size 10
When the budget is emptyFail the request without retrying and count retry_budget_exhausted

6. Circuit breakers

ParameterValue
ScopeExample: one breaker per dependency and per endpoint group, per instance
Failure definitionTimeouts, connection errors and 5xx; not 4xx
Trip thresholdExample: 50% failures with at least 20 requests in a 10 s window
Open intervalExample: 5 s, doubling up to 60 s while probes keep failing
Half-open probesExample: 3 requests; all must succeed to close
Fallback when openPer dependency, see section 13

Breakers and retries must agree: a request rejected by an open breaker is not retried against the same dependency.

7. Bulkheads and concurrency limits

By Little's law the average number of requests in flight equals arrival rate times time in system:

N=λ×WN = \lambda \times W

Example: each Order API instance handles λ=200\lambda = 200 requests/s to inventory with W=0.06W = 0.06 s mean latency, so N=12N = 12 calls in flight on average. A bulkhead of 30 concurrent calls (2.5 times the mean) absorbs normal variance; when inventory slows to 0.5 s, demand would be 100 in flight and the bulkhead rejects the excess instead of letting inventory calls take every worker.

BulkheadResourceLimit per instanceOn full
BH-01 (Example)Inventory client pool30 concurrentFail fast with 503 for checkout
BH-02 (Example)Payment client pool60 concurrentQueue up to 20 with deadline, then fail
BH-03 (Example)Recommendation client pool10 concurrentSkip recommendations
BH-04 (Example)Request workers for batch API vs interactive API20% / 80% of workersReject batch first
[BH-nn][Resource][Limit][Behaviour]

Consider adaptive concurrency limits that adjust the limit from observed latency instead of a fixed number, once fixed limits are proven in tests.

8. Backpressure

  • Bound every queue (in-process, thread pool, message consumer prefetch). Example: request queue of 50 per instance; at 50, reject new work.
  • Prefer queues ordered so fresh work wins under overload: drop requests whose deadline has passed before processing, and consider last-in first-out for interactive traffic when the queue is long.
  • For asynchronous consumers, limit prefetch and in-flight messages, and let the broker hold the backlog. Scale consumers on backlog age, not count.
  • Signal backpressure to callers explicitly: 429 or 503 with Retry-After over HTTP, flow control in streaming protocols.
  • Queue time is latency. Example: at 200 requests/s a queue of 50 adds up to 250 ms; with a 2 s deadline this is acceptable, with 200 ms it is not.

9. Load shedding and admission control

9.1 Criticality classes

The SRE book chapter "Handling Overload" describes four criticality levels propagated with each request. Map your traffic to classes like these:

ClassExample trafficShed order
CRITICAL_PLUSExample: payment confirmation, order status for in-flight checkoutLast; shed only to survive
CRITICALExample: add to cart, checkout start, user-facing readsAfter sheddable classes
SHEDDABLE_PLUSExample: order history page, partial failure acceptableSecond
SHEDDABLEExample: batch exports, prefetch, analytics callbacksFirst

Criticality is set at the edge from the route and propagated to every downstream call; a dependency sheds by the class of the original request.

9.2 Admission control

  • Measure capacity per instance as the throughput at which latency still meets the SLO in a load test. Example: 250 requests/s per instance.
  • Start shedding before saturation. Example: at 90% of measured capacity (225 requests/s) or when the request queue exceeds 30 or CPU exceeds 85%, reject SHEDDABLE; at 100% also reject SHEDDABLE_PLUS; protect CRITICAL classes until the queue deadline check fails.
  • Reject at the cheapest point: before parsing the body or touching the database, with 503 and Retry-After.
  • Account for the cost of rejecting: rejection is cheap but not free, so the load balancer and clients must back off too.

9.3 Client-side throttling

As described in the SRE book, a client can track over a window the number of requests it attempted and accepts the backend took, and reject locally with probability

preject=max⁡(0, requests−K×acceptsrequests+1)p_{reject} = \max\left(0,\ \frac{requests - K \times accepts}{requests + 1}\right)

with K=2K = 2 as the book's usual multiplier. This stops overloaded backends from spending capacity on rejecting requests.

9.4 Goodput under overload

The aim is to keep goodput (work finished within its deadline) close to capacity as offered load rises, instead of letting it collapse. Each request passes this decision before any expensive work starts:

10. Graceful degradation

IDTriggerDegraded behaviourUser impactExit condition
DG-01 (Example)Recommendation breaker openRender page without recommendationsMinorBreaker closed
DG-02 (Example)Pricing unavailableUse cached prices up to 10 minutes old; re-price at paymentSmall risk of price change at paymentPricing healthy for 2 minutes
DG-03 (Example)Load above 100% of capacityDisable order history search; serve last 10 orders onlyReduced featureLoad below 80% for 5 minutes
DG-04 (Example)Event bus unavailableBuffer events in outbox tableNone; notifications delayedBus healthy; outbox drained
[DG-nn][Trigger][Behaviour][Impact][Exit]

Degraded modes must be visible: emit a metric and a log for every request served in a degraded mode, and show the mode on the service dashboard.

11. Idempotency

OperationNaturally idempotentMechanism
GET /orders/{id}YesNone needed
PUT /orders/{id}/addressYes (full replacement)None needed
POST /ordersNoIdempotency-Key header; key, request hash and response stored 24 h
POST /orders/{id}/payNoIdempotency key passed to payment and to the provider
Event consumersNoDeduplicate by event ID in a processed-events table

A repeated key with a different request body is an error (422). Store the idempotency record in the same transaction as the effect, so a crash cannot leave one without the other.

12. Health checks

CheckPurposeWhat it testsMust not test
LivenessRestart a stuck processProcess responds; event loop not blockedAny dependency
ReadinessRemove an instance from rotationLocal resources: warmed caches, connection pool open, not drainingShared dependencies whose failure affects every instance
StartupDelay liveness until initialisedConfiguration loaded, migrations checked
Deep health (dashboard only)DiagnoseDependencies reachableNever used by the load balancer to remove all instances

Rules: fail open if every instance reports unhealthy (keep sending traffic rather than none); stagger restarts; warm up new instances with a slow start on the load balancer so a restarted fleet is not hit at full rate.

13. Per-dependency resilience matrix

DependencyTimeoutRetriesBudgetBreakerBulkheadFallbackDegraded mode
DEP-01 Orders database (Example)300 ms query, 100 ms connect1 on connection error only10%No (pool limits instead)Pool of 40None; fail requestNone
DEP-02 Inventory (Example)250 ms2, idempotent reads10%50% over 10 sBH-01Reserve later at payment for low-risk itemsNone
DEP-03 Pricing (Example)150 ms110%50% over 10 s20 concurrentCached priceDG-02
DEP-04 Payment (Example)1 600 ms or deadline1 with idempotency key5%50% over 30 sBH-02Queue order as "payment pending"None
DEP-05 Recommendations (Example)150 ms0none30% over 10 sBH-03Empty listDG-01
DEP-06 Event bus (Example)200 msRelay retries with backoffn/aNoRelay workers 4Outbox tableDG-04
[DEP-nn][Timeout][Retries][Budget][Breaker][Bulkhead][Fallback][Mode]

14. Testing and fault injection

Test IDFault injectedMechanism verifiedExpected resultEnvironment
FT-01 (Example)Add 2 s latency to recommendationsTimeout, BH-03, DG-01Checkout p99 unchanged; degraded metric risesStaging, then production canary
FT-02 (Example)Payment returns 503 for 50% of callsRetry budget, breakerRetry traffic at or below 5%; breaker opens; orders marked pendingStaging
FT-03 (Example)Load at 2 times capacityShedding by classCRITICAL classes meet SLO; SHEDDABLE rejected with 503Load test environment
FT-04 (Example)Kill 30% of instancesHealth checks, slow startNo crash loop; recovery within 2 minutesGame day
FT-05 (Example)Database connection exhaustionPool limits, fail fastErrors bounded; no thread starvationStaging
[FT-nn][Fault][Mechanism][Result][Environment]

Plan individual experiments with Chaos Experiment Plan Template (ops/chaos-experiment) and team exercises with Game Day Plan Template (ops/game-day-plan).

15. Metrics and alerts

SignalMetricAlert
GoodputSuccessful requests/s by criticality classCRITICAL success below SLO for 5 min
Shed rateRejected requests/s by class and reasonAny CRITICAL_PLUS shed
Retry ratioRetries / requests per dependencyAbove budget for 5 min
Breaker stateOpen breakers per dependencyOpen for more than 2 min
Bulkhead saturationIn-flight / limit per bulkheadAbove 90% for 5 min
Queue timep99 time in request queueAbove 25% of deadline
Deadline dropsRequests dropped as expiredRising trend vs. baseline
Degraded modeRequests served per degraded modeAny mode active for more than 30 min

Tie alert thresholds to the error budget in SLO Document Template (dev/slo-doc) and signal definitions to Observability Specification Template (OpenTelemetry) (ops/observability-spec).

16. Decisions, risks and traceability

16.1 Decisions

IDDecisionAlternativesReason
DEC-01 (Example)Retries only in the client library closest to each dependencyRetries at every layerAvoids amplification (5.3)
DEC-02 (Example)Readiness excludes shared dependenciesDeep readinessPrevents fleet-wide removal
DEC-03 (Example)Fixed bulkheads first, adaptive limits laterAdaptive from day oneSimpler to test and reason about
[DEC-nn][Decision][Alternatives][Reason]

16.2 Risks

IDRiskLikelihoodImpactMitigationOwner
R-01Example: Shedding thresholds drift as code changes capacityMediumHighQuarterly load test; thresholds in config[@name]
R-02Example: Clients ignore Retry-AfterHighMediumClient SDK enforces backoff; edge rate limits[@name]
R-03Example: Degraded pricing causes customer complaintsLowMediumRe-price at payment; notify on change[@name]
[R-nn][Risk][L / M / H][L / M / H][Mitigation][@name]

16.3 Traceability

ObjectiveFailure modesMechanismsTests
RO-01FMD-01, FMD-02Timeouts (4), BH-03, DG-01, matrix row DEP-05FT-01
RO-02FMD-04Shedding (9), backpressure (8)FT-03
RO-03FMD-02, FMD-04Retry budget (5.4), breakers (6)FT-02
RO-04FMD-05, FMD-07Health checks (12), breaker half-openFT-04
[RO-nn][Modes][Mechanisms][Tests]

17. Glossary and references

17.1 Glossary

TermMeaning
DeadlineAbsolute time by which the caller needs an answer, propagated down the call chain
GoodputUseful work completed within its deadline, as opposed to raw throughput
Retry budgetUpper bound on retries as a share of requests
BulkheadResource partition that limits how much of a service one dependency or workload can consume
Load sheddingDeliberately rejecting some requests to keep serving the rest within target
BackpressureSignal from a consumer that makes a producer slow down
CriticalityImportance class carried with a request that decides shed order

17.2 References

ReferenceUse
Beyer, Jones, Petoff and Murphy (eds.), Site Reliability Engineering, O'Reilly, 2016, chapter 21 "Handling Overload" (sre.google/sre-book)Criticality, client throttling, retry budget (9.1, 9.3, 5.4)
Site Reliability Engineering, chapter 22 "Addressing Cascading Failures"Failure model, deadlines, health checks (3, 4, 12)
Amazon Builders' Library, "Timeouts, retries, and backoff with jitter"Timeout selection, jitter, local retry limiting (4, 5)
Amazon Builders' Library, "Using load shedding to avoid overload"Admission control and goodput (9)
Software FMEA Template (IEC 60812) (ops/fmea-software)Scoring failure modes
Capacity Plan Template (ops/capacity-plan)Capacity figures used in 9.2

Standard and licence note

Based on publicly documented industry practice, in particular the Google Site Reliability Engineering book chapters and the Amazon Builders' Library articles listed in 17.2; criticality level names and the client throttling formula are cited with attribution. No text from those works is reproduced. Check the current version of each source. Numbers are illustrative assumptions. Original text written for this collection. Template licence: MIT.

Ähnliche Vorlagen