Knowledge Guide
HomeSystem DesignCapacity Estimation

hard Traffic Amplification: Fan-out & Retry Storms

The frontend QPS you estimated is a floor, not the real number

A single user-facing request is answered by many internal calls, and under stress those calls retry — so backend load is never just "users × requests-per-user." The real number is frontend QPS × fan-out × (1 + retry load), and the retry term does not stay a gentle multiplier: once a dependency degrades, retries feed the very slowness that triggered them, and the multiplier can run away. This is the single biggest reason capacity plans built off "naive user QPS" fall over in production.

Panel A: one frontend request fans out to 20 internal calls, 10,000 req/s times 20 equals 200,000 req/s. Panel B: a retry storm is a positive feedback loop between a slow dependency, timeouts, retries, and more load, pushing effective load from 10,000/s to 30,000/s at retry-probability 2/3, diverging to infinity as p approaches 1
Panel A: one frontend request fans out to 20 internal calls, 10,000 req/s times 20 equals 200,000 req/s. Panel B: a retry storm is a positive feedback loop between a slow dependency, timeouts, retries, and more load, pushing effective load from 10,000/s to 30,000/s at retry-probability 2/3, diverging to infinity as p approaches 1

Multiplier #1 — fan-out: one request, many backends

Almost nothing is served by one service. Opening a social timeline touches auth, the tweet store, the fan-out/ timeline service, per-author profile lookups, media, like/retweet counts, ads, recommendations, feature flags, and a handful of cache shards — a typical page issues on the order of 20 internal API calls for a single request the user experiences as one action.

Call groupCalls per request
tweet fetch + auth2
fan-out / timeline assembly1
author profile lookups3
media (images/video)4
counts, ads, recommendations, cache shards10
Total fan-out factor20
Backend QPS = frontend QPS × fan-out factor.
10,000 req/s (frontend) × 20 (fan-out) = 200,000 req/s hitting internal services.

A capacity plan sized off the 10,000 req/s a user-facing dashboard reports is 20× under before a single retry happens.

Multiplier #2 — retries: a linear cost until it becomes a feedback loop

Clients retry timeouts. Load balancers retry failed upstreams. Services retry their own downstream calls. Under normal, low-failure conditions this is a small, steady tax:

Effective QPS ≈ frontend × fan-out × (1 + retry_rate).
At a steady 5% retry rate: 200,000 × 1.05 = 210,000 req/s.

That (1 + retry_rate) formula is only a safe approximation for small retry rates. The exact mechanism is a feedback loop, not a flat tax: retries are traffic hitting the same struggling dependency, so they add to the arrival rate that the dependency has to serve, which increases queueing and the chance the next call also times out. If p is the probability a call to that dependency needs a retry, the steady-state load actually reaching it is:

effective load = arrivals ÷ (1 − p)

For small p this is close to arrivals × (1 + p) (the first-order approximation above) — but as p grows, the two formulas diverge sharply, because 1/(1-p) is not linear: it blows up as p → 1.

Tracing a retry storm

Take one hop — say the counts service's backing store, which normally takes 10,000 req/s with retries near zero. A GC pause or a hot shard slows it down, so requests start timing out.

StepStateArithmetic
1Baseline, healthy10,000 req/s arrive, p ≈ 0, effective load = 10,000/s
2Dependency slows → timeoutsretry-probability rises to p = 2/3 (two of every three calls now time out and get retried)
3Retries add to arrivalseffective load = 10,000 ÷ (1 − 2/3) = 10,000 ÷ (1/3) = 30,000 req/s (3× the baseline)
4The loop closesthe extra 20,000 req/s queues at the same already-slow store → latency rises further → p climbs toward 1 → effective load → ∞

Step 4 is the retry storm: a positive feedback loop where retries are not a response to the outage, they are part of the outage. The brief GC pause that started it can be over, but the system does not recover on its own — the retry backlog itself is now the bottleneck. This is sometimes called congestion collapse or a metastable failure: a stable, degraded state that persists even after the original trigger clears, because the traffic pattern (not the original cause) is now what's keeping the dependency overloaded.

Pitfalls

Judgment layer — choosing your defenses

Retry budget vs. unlimited retries. Unlimited retries maximize any single caller's chance of riding out a transient blip — fine for rare, isolated, cheap calls. But at scale, many callers share the same dependency, and unlimited retries are exactly the arrivals/(1-p) blow-up above: they actively starve the dependency of the headroom it needs to recover. A retry budget (Google SRE's convention: cap retries to roughly 10% of the request rate over a rolling window) bounds effective load to about 1.1× arrivals no matter how bad p gets — at the cost of occasionally failing a request fast that one more retry would have saved. Trade-off: unlimited retries optimize one caller's success probability; a retry budget optimizes the survival of the shared dependency, which protects everyone's aggregate success. At scale, the budget is the correct default.

Where the circuit breaker goes. Put it on the caller side, wrapping the outbound call, not inside the callee. The point of a breaker is to stop the caller from even attempting the call — and therefore stop generating its retries — once the callee's error rate crosses a threshold. A breaker embedded in the callee can only shed load after the network hop and connection cost already happened, and does nothing to stop the caller's own retry loop; it just relocates the pile-up (a 503 that itself gets retried). Named alternative: server-side load shedding (reject when queue depth exceeds X) is complementary, not a substitute — the breaker protects callers from wasting time on a known-bad dependency; load shedding protects the callee from callers that don't have a breaker yet.

Fan-out-on-write vs. fan-out-on-read. The amplification does not disappear when you redesign around it — it moves. Fan-out-on-write (push: one tweet write becomes N inbox writes at publish time) keeps reads at O(1) but amplifies writes badly for accounts with huge followings. Fan-out-on-read (pull: posting stays O(1), but every timeline read fans out across everyone the user follows) keeps writes cheap but amplifies reads for users who follow many accounts. Trade-off: push pays the amplification cost at write time in exchange for cheap reads (good when reads ≫ writes and follower counts are bounded); pull pays it at read time (good for celebrity-scale write fan-out). Production systems (Twitter's timeline) use a hybrid: fan-out-on-write for ordinary accounts, fan-out-on-read for celebrities — choosing, per entity, which side absorbs the cost.

Takeaways


Re-authored for this guide; fan-out and retry-storm diagrams hand-authored as SVG. Retry-budget and fast-fail model follow the Google SRE Book, "Addressing Cascading Failures" (Ch. 22), and the Google SRE Workbook's retry guidance; capped exponential backoff with jitter follows the AWS Architecture Blog, "Timeouts, retries, and backoff with jitter" (Marc Brooker). See also: Tail Latency & Fan-out Amplification, Back-pressure & Flow Control, Circuit Breaker — The State Machine.

🤖 Don't fully get this? Learn it with Claude

Stuck on Traffic Amplification: Fan-out & Retry Storms? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Traffic Amplification: Fan-out & Retry Storms** (System Design) and want to truly understand it. Explain Traffic Amplification: Fan-out & Retry Storms from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Traffic Amplification: Fan-out & Retry Storms** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Traffic Amplification: Fan-out & Retry Storms** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Traffic Amplification: Fan-out & Retry Storms** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes