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.
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 →