HAMZA KAREEM / CONCEPTS hamzawi.dev

Lesson 482 min read

Tail Latency Amplification

why your p99 lies

System designsystem design / performance

The myth

"Our service p99 is 100ms. So 99% of users get a fast page. That 1% tail is a rounding error — I'll optimize the average instead."

Actually

A user request is almost never ONE service call. Your page calls auth, cart, prices, inventory, recommendations… say 20 backends. The user waits for the SLOWEST one.

Chance that at least one of 20 calls lands in your 1% tail:

1 − 0.99^20 = 18%

Your "1% tail" is ~1 in 5 page loads. Your p99 is the user's p82.

At 100 calls: 1 − 0.99^100 = 63%. Now the MAJORITY of page loads is paced by your worst case.

Prove it in 10 seconds

python3 -c "

import random
c=lambda: 10 if random.random()<0.99 else 500
n=100000
one=sum(c()>10 for _ in range(n))/n
fan=sum(max(c() for _ in range(20))>10 for _ in range(n))/n

print(round(one,3), round(fan,3))"

# → 0.01 0.182

Same backend. Same p99. 18x more slow users.

The rule to keep

For fan-out N, the user-level experience tracks per-call percentile^N. To give a 20-way page a real p99, each backend needs a good p99.95 — not p99.

Nobody graphs p99.95. That's why the dashboard is green while people complain.

Where the tail comes from (rarely "slow code")

  • GC pause, JIT deopt
  • Cold pool connection: TLS handshake + TCP slow start
  • Queueing — the big one. Wait time scales as 1/(1−ρ). At 70% utilization you already carry ~2x service time; at 90% it's 10x. Capacity headroom IS a latency feature.
  • Noisy neighbor / CPU throttling
  • One slow shard out of 32

Three fixes that actually move p99

  1. Hedged requests — fire to replica A; if nothing back by the p95 mark, fire a duplicate to B and take whichever answers first. Dean & Barroso's "The Tail at Scale": hedging after 10ms cut p99.9 from 1800ms → 74ms for ~2% extra requests.
  2. Shrink the fan-out — 20 parallel calls is a latency decision, not just an architecture one. Merge or precompute.
  3. Per-call timeout + fallback — one slow dependency should degrade the page (stale recs, hidden widget), not define it.

The gotcha

Hedging and retrying look identical and behave oppositely under load. A naive retry fires hardest exactly when the system is already saturated → self-inflicted outage. Always cap hedges as a budget (e.g. max 5% of traffic) and never hedge non-idempotent writes.

Your exercise

Open your slowest page in devtools, count the network calls it blocks on (N). Compute 1 − 0.99^N — that's the share of your users sitting in your p99 today.

Then answer: which ONE of those calls would you hedge first, and what delay would you fire the hedge at? (Hint: not p99 — that's too late to help.)