Skip to content
About
Main content

Tail at scale, and why percentiles do not combine

Why does fan-out turn a healthy per-node p99 into a bad system p99, and why can't you average percentiles?

Tail at scale

(From Dean and Barroso's paper "The Tail at Scale".)

The arithmetic is short and the consequence large. Send a request to N independent nodes and wait for all. If each node is slow with probability p, then P(all fast) = (1 − p)^N.

Example: per-node means p = 0.01. With N = 100: 1 − 0.99¹⁰⁰ = 1 − 0.366 = 63% of requests meet at least one slow node. Your p99 became your p63.

RelationshipTail at scale →
probability that one node is slow (p = 0.01 for a per-node p99)
number of independent nodes the request waits for
per-node p99p99.9p99.99
Data table
Share of requests that meet at least one slow node
Fan-out NseriesRequests slowed
1per-node p991%
1.12per-node p991.12%
1.26per-node p991.26%
1.41per-node p991.41%
1.58per-node p991.58%
1.78per-node p991.77%
2per-node p991.99%
2.24per-node p992.22%
2.51per-node p992.49%
2.82per-node p992.79%
3.16per-node p993.13%
3.55per-node p993.5%
3.98per-node p993.92%
4.47per-node p994.39%
5.01per-node p994.91%
5.62per-node p995.49%
6.31per-node p996.14%
7.08per-node p996.87%
7.94per-node p997.67%
8.91per-node p998.57%
10per-node p999.56%
11.2per-node p9910.7%
12.6per-node p9911.9%
14.1per-node p9913.2%
15.8per-node p9914.7%
17.8per-node p9916.4%
20per-node p9918.2%
22.4per-node p9920.1%
25.1per-node p9922.3%
28.2per-node p9924.7%
31.6per-node p9927.2%
35.5per-node p9930%
39.8per-node p9933%
44.7per-node p9936.2%
50.1per-node p9939.6%
56.2per-node p9943.2%
63.1per-node p9947%
70.8per-node p9950.9%
79.4per-node p9955%
89.1per-node p9959.2%
100per-node p9963.4%
112per-node p9967.6%
126per-node p9971.8%
141per-node p9975.8%
158per-node p9979.7%
178per-node p9983.3%
200per-node p9986.5%
224per-node p9989.5%
251per-node p9992%
282per-node p9994.1%
316per-node p9995.8%
355per-node p9997.2%
398per-node p9998.2%
447per-node p9998.9%
501per-node p9999.4%
562per-node p9999.6%
631per-node p9999.8%
708per-node p9999.9%
794per-node p99100%
891per-node p99100%
1Kper-node p99100%
1.12Kper-node p99100%
1.26Kper-node p99100%
1.41Kper-node p99100%
1.58Kper-node p99100%
1.78Kper-node p99100%
2Kper-node p99100%
2.24Kper-node p99100%
2.51Kper-node p99100%
2.82Kper-node p99100%
3.16Kper-node p99100%
3.55Kper-node p99100%
3.98Kper-node p99100%
4.47Kper-node p99100%
5.01Kper-node p99100%
5.62Kper-node p99100%
6.31Kper-node p99100%
7.08Kper-node p99100%
7.94Kper-node p99100%
8.91Kper-node p99100%
10Kper-node p99100%
1p99.90.1%
1.12p99.90.112%
1.26p99.90.126%
1.41p99.90.141%
1.58p99.90.158%
1.78p99.90.178%
2p99.90.199%
2.24p99.90.224%
2.51p99.90.251%
2.82p99.90.282%
3.16p99.90.316%
3.55p99.90.354%
3.98p99.90.398%
4.47p99.90.446%
5.01p99.90.5%
5.62p99.90.561%
6.31p99.90.629%
7.08p99.90.706%
7.94p99.90.792%
8.91p99.90.888%
10p99.90.996%
11.2p99.91.12%
12.6p99.91.25%
14.1p99.91.4%
15.8p99.91.57%
17.8p99.91.76%
20p99.91.98%
22.4p99.92.21%
25.1p99.92.48%
28.2p99.92.78%
31.6p99.93.11%
35.5p99.93.49%
39.8p99.93.9%
44.7p99.94.37%
50.1p99.94.89%
56.2p99.95.47%
63.1p99.96.12%
70.8p99.96.84%
79.4p99.97.64%
89.1p99.98.53%
100p99.99.52%
112p99.910.6%
126p99.911.8%
141p99.913.2%
158p99.914.7%
178p99.916.3%
200p99.918.1%
224p99.920.1%
251p99.922.2%
282p99.924.6%
316p99.927.1%
355p99.929.9%
398p99.932.9%
447p99.936%
501p99.939.4%
562p99.943%
631p99.946.8%
708p99.950.8%
794p99.954.8%
891p99.959%
1Kp99.963.2%
1.12Kp99.967.5%
1.26Kp99.971.6%
1.41Kp99.975.7%
1.58Kp99.979.5%
1.78Kp99.983.1%
2Kp99.986.4%
2.24Kp99.989.4%
2.51Kp99.991.9%
2.82Kp99.994%
3.16Kp99.995.8%
3.55Kp99.997.1%
3.98Kp99.998.1%
4.47Kp99.998.9%
5.01Kp99.999.3%
5.62Kp99.999.6%
6.31Kp99.999.8%
7.08Kp99.999.9%
7.94Kp99.9100%
8.91Kp99.9100%
10Kp99.9100%
1p99.990.01%
1.12p99.990.011%
1.26p99.990.013%
1.41p99.990.014%
1.58p99.990.016%
1.78p99.990.018%
2p99.990.02%
2.24p99.990.022%
2.51p99.990.025%
2.82p99.990.028%
3.16p99.990.032%
3.55p99.990.036%
3.98p99.990.04%
4.47p99.990.045%
5.01p99.990.05%
5.62p99.990.056%
6.31p99.990.063%
7.08p99.990.071%
7.94p99.990.079%
8.91p99.990.089%
10p99.990.1%
11.2p99.990.112%
12.6p99.990.126%
14.1p99.990.141%
15.8p99.990.158%
17.8p99.990.178%
20p99.990.199%
22.4p99.990.224%
25.1p99.990.251%
28.2p99.990.281%
31.6p99.990.316%
35.5p99.990.354%
39.8p99.990.397%
44.7p99.990.446%
50.1p99.990.5%
56.2p99.990.561%
63.1p99.990.629%
70.8p99.990.705%
79.4p99.990.791%
89.1p99.990.887%
100p99.990.995%
112p99.991.12%
126p99.991.25%
141p99.991.4%
158p99.991.57%
178p99.991.76%
200p99.991.98%
224p99.992.21%
251p99.992.48%
282p99.992.78%
316p99.993.11%
355p99.993.49%
398p99.993.9%
447p99.994.37%
501p99.994.89%
562p99.995.47%
631p99.996.11%
708p99.996.84%
794p99.997.64%
891p99.998.53%
1Kp99.999.52%
1.12Kp99.9910.6%
1.26Kp99.9911.8%
1.41Kp99.9913.2%
1.58Kp99.9914.7%
1.78Kp99.9916.3%
2Kp99.9918.1%
2.24Kp99.9920.1%
2.51Kp99.9922.2%
2.82Kp99.9924.6%
3.16Kp99.9927.1%
3.55Kp99.9929.9%
3.98Kp99.9932.8%
4.47Kp99.9936%
5.01Kp99.9939.4%
5.62Kp99.9943%
6.31Kp99.9946.8%
7.08Kp99.9950.7%
7.94Kp99.9954.8%
8.91Kp99.9959%
10Kp99.9963.2%

Equivalently, the p99 of a 100-way fan-out is about the per-node p99.99. To get two nines from the system you need four nines from the parts. The more nodes you fan out to, the stricter the tail requirement, which makes the tail a distributed-systems problem, not a single-service problem.

Independence makes this estimate too optimistic. Correlated slowness ( pauses, a shared hot resource, a bad rack, the SLC-cache cliff from Storage media — a consumer SSD that writes fast into a small fast buffer and slows suddenly when it fills) makes real behavior worse than the formula.

Mitigations all reduce variance, and :

  • Hedged requests: send a copy to another replica after the p95 time has passed. A few percent more load, a tail improvement of about 10×.
  • Tied requests: send to two replicas at once, each able to cancel the other.
  • Micro-partitioning: make work units small, so a slow one costs little.
  • Selective replication of hot data.
  • : answer with what you have at time T.

This is the branchless-code trade from CPU and memory: pay a small guaranteed cost to remove a large variable one.

Design conclusion: reduce your fan-out where you can. N is in the exponent. Reducing fan-out from 100 to 20 helps your tail more than making every node 2× faster.


Percentiles do not combine

The core mistake: p99 is not a quantity. It is a position in a distribution. Averaging positions has no meaning. Averaging ten servers' p99 values tells you nothing about the p99 of the fleet; you need the merged distribution.

Three common failures in real dashboards:

  1. Across servers. Merge distributions (histograms, t-digest, HDR histogram — compact structures that store the shape of a distribution), do not average summaries. This is why Prometheus histograms can be aggregated and Prometheus summaries cannot.
  2. Across time. Averaging 1-minute p99 values to get an hourly p99 is wrong. Store the buckets and compute the when you query.
  3. Across sequential stages. p99(A) + p99(B) ≠ p99(A + B). If A and B are independent, the p99 of the sum is lower than the sum of p99s (both being slow together is rarer). If they are correlated, it can be higher. The simple sum is wrong in an unknown direction, which is worse than being wrong in a known one.

Most monitoring stacks average percentiles somewhere in the pipeline, silently. "We monitor p99" is a claim worth checking against your own dashboards (Check percentile aggregation in your monitoring).


What the performance laws forbid

What this article adds: the earlier parts explained why costs exist. This article explains why systems fail in a non-linear way. The hyperbola, the 's N² term and the tail's exponent are all non-linear. Systems do not get worse in proportion. They are fine, fine, fine, and then fail suddenly. This is the most important operational fact across the platform.

LawWhat it forbidsWay out
without concurrencyPut more work in flight
Queueing (Kingman)High and low latencyKeep headroom, or reduce variance
Amdahl / USLUnlimited speedup; and after N*, any speedupReduce serial fraction (α) and coordination (β)
Tail at scaleSystem tail ≤ component tailReduce fan-out, hedge, replicate

And about averages: every law here is invisible in average-based monitoring. A system at 80% utilization looks fine on a dashboard and is one spike from collapse. A 100-way fan-out with healthy per-node p99 has a bad user-facing p99. Averaged p99 across a fleet can look flat while the real p99 doubles. The mathematics of this article is exactly the mathematics that averages destroy.