A row of ten runners crossing a finish line together except for one far behind, long shadows, dusk Tech
AI-generated, Working Theory
Tech · ◉ Evergreen

At scale, your average doesn't matter — your tail does

by · ·4 min·Working Theory

Under fan-out, the slowest call sets the whole request's speed. Why the tail dominates, and how hedged requests tame it cheaply.

Every latency graph you’ve ever stared at is lying to you a little, and the lie is the average. A single number in the middle of the distribution feels like “how fast the system is.” It isn’t. At any real scale, the thing your users actually feel is the tail — the slow 1% — and there’s a mathematical reason the tail escapes the cage you think you’ve put it in.

Here’s the mechanism. One user-facing request rarely hits one server. It fans out: to render a page you might call dozens or hundreds of backend services, shards, or replicas in parallel, and you can’t answer the user until the slowest of them comes back. So the latency you ship isn’t the average of those calls. It’s the maximum. And maxima are cruel. Suppose each individual call is quick almost always but has just a 1% chance of taking longer than a second — a p99 of one second, which looks fine on a dashboard. Fan out to a hundred parallel calls and the chance that at least one of them lands in that slow 1% is 1 − 0.99¹⁰⁰, about 63%. Read that again: a one-in-a-hundred slowness at the component level becomes a nearly two-in-three slowness at the request level. The rare tail of one server becomes the ordinary experience of the whole system. Jeff Dean and Luiz Barroso named this “the tail at scale,” and once you see it you can’t unsee it.

1 request the slowest call sets your total parallel backend calls (bar length = latency) a hedged request send to A A is stuck in the tail… p95 elapsed → send a copy to B B answers first — take it, cancel A
Under fan-out the maximum, not the mean, is what the user waits for. A hedged request duplicates only the slow tail: after the p95 wait, a copy goes to a second replica and the first answer wins. Original diagram · Working Theory

The instinct is to fix this by making every server uniformly faster — chase the tail down to zero. That’s a losing fight. Tails come from things you can’t fully eliminate: a garbage-collection pause here, a queue backing up there, a background compaction, contention on a shared disk, a noisy neighbor on the same box. Somewhere across a hundred machines, one is always having a slightly bad moment. So the tolerant systems don’t try to abolish the tail. They route around it.

The cleverest trick is the hedged request. Send your request to one replica. If it hasn’t answered by the time you’d normally expect it to — say, the 95th percentile of usual response time — send the same request to a second replica, and take whichever answers first, cancelling the loser. The beauty is in what it costs. You aren’t duplicating everything; you’re only duplicating the slow tail, the ~5% that crossed your patience threshold. A few percent of extra load buys a dramatic cut in p99, because the odds that both replicas hit a bad moment at once are tiny. A tighter cousin, the tied request, sends to two replicas at once but tells each about the other, so the instant one starts real work it cancels its twin — trading a sliver more coordination for even less wasted effort.

Why not just retry everything twice and take the fastest? Because that doubles your load to fix a problem that lives in 1% of calls, and doubling load tends to create the very contention that makes tails in the first place. The whole art is precision: spend redundancy only where and when slowness actually shows up. (It also assumes the work is safe to send twice — a good reason your read paths, at least, should be idempotent.)

The build decision underneath all of this is a shift in what you measure and design toward. Latency is a distribution, not a number. If your alerts, your SLOs, and your intuitions all point at the mean, you’re optimizing the part of the system almost nobody feels while the part everybody feels drifts. Design for p99 — and if you fan out widely, for p99.9 — and treat the occasional slow server as a permanent fact of life to be tolerated, not a bug to be finally squashed.

The one-liner I’d tape to the monitor: your users don’t live at the median. They live in the tail, and the tail is the only latency worth designing for.

Worth looking up: Jeff Dean & Luiz André Barroso, “The Tail at Scale,” Communications of the ACM, 2013 — hedged requests, tied requests, and tail-tolerant system design.

Sources

  • Dean & Barroso, 'The Tail at Scale,' CACM 2013 — hedged requests, tied requests

Liked this? Get the next one in Working Theory.

Going weekly in August (it's in beta now). One genuinely interesting read on building, the brain, and the science most people missed.

Subscribe →
Got a reaction, a counter-example, or something I missed? Reply by email — I read everything.
◉ join in

Where have you hit this — in a product you use, or one you're building?

Threads open here soon. For now, the conversation lives two clicks away — discuss on GitHub, or just reply by email. I read and answer everything.