A11 · Part 3 · Advanced
Capacity estimation
The whiteboard arithmetic that turns hand-waving into a design — no calculator, about three minutes, out loud.
08On this page
Why they make you do arithmetic
Capacity estimation looks like a party trick and is actually the load-bearing part of the interview. Nobody cares whether you said 30 TB/day or 40 TB/day. What the arithmetic does is force every architectural decision that follows to have a reason. "We'll need a CDN" is a guess. "Peak egress is around a terabit per second, so serving from origin would need forty 25-gig links; we'll put a CDN in front and target a 95% hit ratio" is a design. The numbers are how you stop the interview from being an opinion exchange.
The second reason is negative: estimation is the fastest way to discover that you don't need the thing you were about to draw. Roughly half the value of the exercise is in the moments when the number comes back small and you get to say "so a single Postgres box covers this for three years." That sentence scores higher than any amount of Kafka.
The rounding conventions that make it tractable
You have no calculator and you are talking while you compute. Every convention below exists to keep the arithmetic to one significant figure and a power of ten.
| Quantity | True value | Use this | Error, and which way |
|---|---|---|---|
| Seconds in a day | 86,400 | 100,000 = 105 | Rate estimates come out ~14% low. Irrelevant next to a 3× peak multiplier. |
| Seconds in a month | 2,592,000 | 2.5 × 106 | Under 4% off. |
| Seconds in a year | 31,536,000 | 3 × 107 | ~5% low. (The famous mnemonic: π × 107.) |
| Days in 5 years | 1,825 | 2,000 | ~10% high — conservative, which is the right direction for storage. (The worked example below uses the exact 1,825 to keep its totals checkable.) |
| 1 KB / MB / GB / TB / PB | 210, 220, 230, 240, 250 | 103, 106, 109, 1012, 1015 | 7% low at GB, 10% at TB. Say "I'm using powers of ten" once and move on. |
| Peak-to-average traffic | varies | 2-3× (10× if event-driven: ticket sales, live sport, New Year) | State which one you chose and why. |
| Fraction of DAU concurrent at peak | varies | 10-25% | Only matters for connection-oriented systems. |
| Storage replication overhead | varies | 3× for replicas, 1.4× for erasure coding | Forgetting this is the single most common estimation miss. |
One number does half the work
A day is 100,000 seconds. Every "per day" figure becomes a "per
second" figure by moving the decimal point five places. 2 billion requests
a day is 20,000 a second, and you did that in your head while still talking.
The order — always the same eight steps
Two habits make this fluent. First, write the assumptions on the board before the arithmetic — "10 sessions/user/day, 3× peak, 5-year horizon" — so the interviewer can correct an input instead of watching you compute the wrong thing for two minutes. Second, say the units out loud every line. Almost every estimation error in an interview is a units error: bits versus bytes, per-day versus per-second, one photo versus one photo plus its four derived sizes.
Numbers worth memorizing
These are rounded planning numbers, not measurements. They blend the original list usually credited to Jeff Dean (and, before him, Peter Norvig) with Colin Scott's 2020 extrapolation, and the two disagree in places: the original has an L1 reference at 0.5 ns, a branch mispredict at 5 ns, a mutex at 25 ns, 1 MB read from memory at 250 µs, and a 150 ms round trip between California and the Netherlands; the 2020 extrapolation has L1 at 1 ns, 1 MB from memory at 3 µs, an SSD random read at 16 µs and a disk seek at 3 ms. Memorise the orders of magnitude, not the digits.
| Operation | Time (rounded) | Anchor |
|---|---|---|
| L1 cache reference | ~1 ns | the unit everything else is measured in |
| Branch mispredict | ~3-5 ns | |
| L2 cache reference | ~4-7 ns | |
| Mutex lock/unlock, uncontended | ~20-25 ns | |
| Main memory reference | 100 ns | 100× slower than L1 — this is why cache locality wins |
| Compress 1 KB | ~2 µs | compression usually costs less than the network hop it saves, when the data compresses well |
| Read 1 MB sequentially from RAM | ~50 µs | ≈ 20 GB/s on current servers; the old list says 250 µs, and a naive extrapolation says 3 µs |
| SSD random read (NVMe, with queueing) | ~100 µs | ultra-low-latency flash does ~10-20 µs; ordinary TLC NVMe is typically 50 µs and up, and the rest is the software stack |
| Read 1 MB from NVMe SSD | ~300 µs | ≈ 3 GB/s |
| Round trip within one availability zone | ~0.5 ms | your budget for a service-to-service hop; cross-AZ in one region is 1-2 ms |
| Read 1 MB sequentially from spinning disk | ~10 ms | ≈ 100 MB/s (the old list says 20 ms) |
| Disk seek (HDD) | ~3-10 ms | why random I/O on HDD is a design error, not a tuning problem |
| Round trip US east to US west | ~60-70 ms | the straight-line floor is 4,800 km at 200,000 km/s in fibre = 24 ms each way, ~48 ms round trip; real routes are longer. Physics sets the floor, not engineering. |
| Round trip US east to western Europe | ~70-90 ms | New York to London is about 70 ms |
| Round trip US east to India / Singapore / Australia | ~200-230 ms | the reason "just put it in one region" fails a global product |
| Component | Throughput to assume | Note |
|---|---|---|
| Single relational primary (Postgres/MySQL), modern NVMe server, warm cache | Planning figure: ~20,000 simple indexed point reads/s and ~5,000 committed writes/s | Conservative planning numbers, not limits. With batching and group commit, strong hardware does several times more (reports of 100,000+ reads/s and 20,000-50,000 writes/s), and OpenAI has described running ChatGPT on one Azure PostgreSQL primary with about 50 replicas at millions of aggregate queries per second. Plan a change when sustained reads pass ~20k/s or sustained writes pass ~5k/s, and treat ~20k+ sustained writes as "I am sharding or queueing now". Measure; do not assume. |
| Read replica | Planning figure: another ~20,000 simple reads/s each | Replicas scale reads, never writes. Say this every time you add one. |
| Redis, single instance | ~100,000 ops/s; up to ~1,000,000 pipelined (the Redis docs show 70,000-190,000 non-pipelined and 1.5 million+ pipelined on commodity hardware) | Single-threaded for command execution — one hot key cannot be scaled by adding RAM. |
| Application server, real JSON handler with a DB call | 1,000-5,000 rps | Use 1,000 for sizing. It is conservative and defensible. |
| nginx / envoy serving static or proxying | Planning figure: ~50,000 rps per box | |
| Kafka broker | Planning figure: ~100 MB/s sustained per broker | Sequential disk writes; the bottleneck is usually the NIC or disk. Tuned clusters on better hardware can do more. LinkedIn's well-known 2014 benchmark reached about 190 MB/s of producer traffic into a three-broker cluster with replication factor 3, so each broker wrote roughly that much on six disks: a tuned best case, which shows the planning figure is conservative rather than a rate to expect by default. |
| One 10 / 25 Gbps NIC | 1.25 / 3.1 GB/s | Divide by 8. Bandwidth is quoted in bits, storage in bytes — this is the classic slip. |
| One commodity server, 2026 | 64-128 cores, 256 GB-2 TB RAM, tens of TB NVMe | Bigger than most candidates assume. Vertical scaling gets you further than the folklore suggests. |
| Thing | Bytes |
|---|---|
| char / boolean / int / bigint or timestamp / UUID | 1 / 1 / 4 / 8 / 16 |
| A "skinny" row — a few ids and a timestamp | ~100 B |
| A typical metadata row with short text | ~500 B - 1 KB |
| A chat message (text + delivery metadata) | ~200 B |
| A structured JSON log line | ~500 B - 1 KB |
| A thumbnail / a web-sized image / a phone photo | ~20 KB / ~200 KB / 1-5 MB |
| One minute of 1080p video | ~50 MB |
Worked example 1 — a photo-sharing service
Assumptions stated first, on the board, before any arithmetic: 200 M daily active users; each opens the app 10 times a day and each open loads one feed page of 20 images; 10% of users post one photo per day; 5-year retention; peak is 3× average.
TRAFFIC
DAU 200,000,000
feed opens / user / day 10
feed reads / day 2 x 10^9 // 200M x 10
seconds / day 100,000
avg feed reads / sec 20,000 // 2e9 / 1e5
PEAK feed reads / sec 60,000 // x3 — this sizes the fleet
posters / day 20,000,000 // 10% of 200M
avg uploads / sec 200 // 2e7 / 1e5
PEAK uploads / sec 600
read : write ratio 100 : 1 // 2e9 vs 2e7 -> read-heavy, cache hard
BLOB STORAGE
bytes / photo 1.5 MB // 1.2 MB original + 4 derived sizes
per day 20e6 x 1.5e6 = 3 x 10^13 B = 30 TB/day
per year 30 TB x 365 = 10,950 TB ~ 11 PB/year
over 5 years ~55 PB raw
with 3x replication ~165 PB
with erasure coding 1.4x ~77 PB // worth 88 PB of savings — say this out loud
METADATA STORAGE
bytes / photo row 500 B // ids, timestamps, caption, url, counters
per day 20e6 x 500 = 10 GB/day
per year 3.65 TB/year
over 5 years ~18 TB // ONE box. Do not shard this on day one.
BANDWIDTH (egress)
bytes / feed page 20 images x 100 KB = 2 MB
per day 2e9 x 2e6 = 4 x 10^15 B = 4 PB/day
avg egress 4e15 / 1e5 = 4 x 10^10 B/s = 40 GB/s = 320 Gbps
PEAK egress ~960 Gbps ~ 1 Tbps // serving this from origin is not a plan
with a 95%-hit CDN origin sees ~48 Gbps // two or three 25G links. Feasible.
CACHE
hot set: metadata for the last 7 days of photos
rows 20e6 x 7 = 1.4 x 10^8
memory 1.4e8 x 500 B = 70 GB // 3-node Redis + replicas. Trivial.
SERVERS
peak req/s 60,000
per app server 1,000 rps
bare minimum 60
x2 for headroom + AZ loss tolerance ~120 app servers
Every one of those lines is a sentence you say while writing it. The interviewer is not checking your multiplication — they are checking that you know which quantity comes next and that you noticed the two interesting results: metadata is small enough for one machine, and blob egress is large enough to make the CDN non-negotiable.
Three refinements worth one sentence each. Cache sizing: a common rule of thumb is that about 20% of the data serves about 80% of the reads, so start by caching the hottest fifth of a day's read volume (a planning figure, not a law; measure the real skew). Headroom: the flat "×2" above is a planning multiplier; in practice you load-test to the point where p99 latency starts to climb and keep peak utilisation around 60-70% of that, because queues grow faster than linearly as a server fills. Cost: once you have a byte count and a server count, multiply by a price (storage per GB-month, egress per GB, instance-hours) before you propose something exotic; the bill is often what decides between two designs that both fit.
⚠ The three misses that cost candidates the most
(1) Forgetting replication and derived data — a 55 PB answer that
ignores 3× replicas is off by a factor of three, and the fix is one
sentence. (2) Confusing bits and bytes when quoting bandwidth;
40 GB/s is 320 Gbps, not 40 Gbps. (3) Estimating average load and
then sizing the fleet from it. Systems fail at peak, so the fleet is sized
from peak, and the peak multiplier is an assumption you must state.
Worked example 2 — a chat service
Same eight steps, wildly different shape of answer — which is exactly why it is worth doing twice. Assumptions: 500 M DAU; 40 messages sent per user per day; average message reaches 3 recipients (a mix of 1:1 and small groups); 20% of DAU are connected simultaneously at peak.
TRAFFIC
DAU 500,000,000
messages sent / day 500e6 x 40 = 2 x 10^10
avg sends / sec 200,000 // 2e10 / 1e5
PEAK sends / sec 600,000
avg recipients / message 3
deliveries / day 6 x 10^10
avg deliveries / sec 600,000
PEAK deliveries / sec 1,800,000 // the real workload is delivery, not send
STORAGE (if you keep history)
bytes / message 200 B // text + ids + timestamps + delivery state
per day 2e10 x 200 = 4 x 10^12 B = 4 TB/day
per year 1.46 PB/year
x3 replication ~4.4 PB/year // LSM store, partition by conversation
STORAGE (if you keep only the undelivered)
~1% undelivered at any time, held ~1 day
4 TB x 1% = 40 GB // five orders of magnitude cheaper
CONNECTIONS
concurrent at peak 500e6 x 20% = 100,000,000 sockets
memory / socket 10-50 KB, use 20 KB // kernel buffers + TLS + per-user state
total connection RAM 1e8 x 2e4 = 2 x 10^12 B = 2 TB
sockets / gateway box 250,000 // planning figure 250k-500k; not the 2M+ record below
gateway boxes 100e6 / 250e3 = 400, call it 500 with headroom
BANDWIDTH
peak 1.8e6 deliveries/s x 200 B = 3.6 x 10^8 B/s
= 360 MB/s ~ 3 Gbps // compare: 1 Tbps for the photo service
ROUTING TABLE (which gateway holds each live socket?)
100e6 entries x 50 B = 5 GB // fits in one Redis. Do not use a database.
On the per-box number: WhatsApp reported more than 2 million simultaneous connections on one tuned FreeBSD/Erlang server in 2012 (24 logical CPUs, about 96 GB of RAM; the post gives no per-connection memory figure). That is a record, not a plan: use 250,000-500,000 per box unless you are told the hardware and the runtime.
Say it like this → "The interesting result is that
chat is a connection problem, not a bandwidth problem — for text,
3 Gbps at peak is nothing (photos, voice notes and video go down the blob
and CDN path and would dwarf it, so I'd estimate them separately), but 100 million concurrent sockets means the gateway tier
is stateful and I need a routing layer to find a user's socket. And notice
that 'do we retain history?' swings storage from 40 GB to 4.4 PB a year.
That is a product decision with a five-order-of-magnitude infrastructure
consequence, so I'd want it answered before I draw the storage layer."
How each number cashes out as a design decision
| The number you computed | What it rules out | What it rules in |
|---|---|---|
| 60,000 peak reads/sec | A single database primary serving reads (60k/s is three times the ~20k/s planning figure) | Cache tier in front, read replicas behind, ~120 stateless app servers |
| 100:1 read:write ratio | Optimising for write throughput; normalised schemas with joins on the read path | Denormalised read models, aggressive caching, fan-out-on-write (see the case-studies chapter) |
| 30 TB/day of blobs | Storing images in the database. Ever. | Object storage + CDN; the DB holds a 500-byte row with a URL |
| 18 TB of metadata over 5 years | Sharding into 100 shards on day one | One primary + replicas, with a shard key chosen now and applied later |
| ~1 Tbps peak egress | Serving from origin, single-region | CDN with an explicit hit-ratio target; cache keys designed for hit ratio |
| 100 M concurrent sockets | Stateless HTTP polling; a stateless gateway tier | Persistent connections (~400-500 gateway boxes at 250k each), sticky routing, a socket-location registry, graceful drain on deploy |
| 5 GB routing table | A database lookup on every message delivery | In-memory table, replicated, rebuilt from connection state on restart |
| 600,000 peak writes/sec | A relational primary; synchronous cross-region replication | LSM-tree store partitioned by conversation id, tunable quorum (see the sharding and consistency chapters) |
⚠ Do not over-invest in precision
Spending eight minutes of a forty-five-minute interview on arithmetic is a
failure mode of its own. The target is roughly three minutes: state
assumptions, compute peak QPS, storage, bandwidth, and one memory figure,
then say "these are order-of-magnitude; the ones that change the design are
peak QPS and total storage" and move on. If the interviewer wants a number
refined they will ask. And if they hand you a number — "assume 10 M users" —
take it and stop negotiating; they are trying to save you time.
Dry run: the eight-step order applied to the photo-sharing numbers
| Step | Quantity | Computation | Result |
|---|---|---|---|
| 1 | DAU | given | 200,000,000 |
| 2 | Avg feed reads/sec | (200M × 10 opens) ÷ 100,000 s | 20,000/s |
| 3 | Peak feed reads/sec | 20,000 × 3 | 60,000/s — sizes the fleet |
| 4 | Blob storage/day | 20M posters × 1.5 MB | 30 TB/day |
| 5 | Blob storage / 5 yr | 30 TB × 365 × 5 = 54.75 PB raw; then × 3 replicas, or × 1.4 erasure coding | ~55 PB raw; ~165 PB replicated or ~77 PB erasure-coded — chooses object storage, not the DB |
| 6 | Peak bandwidth | 2 MB/page × 60,000 pages/s × 8 bits/byte | ~960 Gbps — makes a CDN non-negotiable |
| 7 | Cache RAM | 7 days × 20M posts/day × 500 B | 70 GB — trivial, fits a small Redis tier |
| 8 | Servers | 60,000 peak rps ÷ 1,000 rps/box, × 2 headroom | ~120 app servers |
Each step is an input to the next: step 3 sizes the fleet used in step 8, and step 6 is the number that rules out serving images from origin at all. Notice how differently the answers land: step 7's 70 GB is one small Redis cluster, while step 6's 960 Gbps is roughly forty 25-gigabit links, an entire CDN strategy. Quantities in different units are not comparable by size, which is exactly why you do all eight steps instead of stopping at storage.
Recognizing it in an unseen problem
- Every design prompt needs this, whether or not it is asked for. Do it immediately after requirements and before the first box goes on the board — it is what makes the boxes defensible.
- The prompt gives you a user count, a "how would this scale to X", or a product with obvious media (photos, video, voice) — media means the blob path and the metadata path have wildly different sizes and must be estimated separately.
- A naive answer estimates average load. The senior move is peak load, with the multiplier stated as an assumption, plus a sentence about what drives the peak for this specific product.
- Distinguish "big number" from "hard problem": 18 TB of metadata is a big number and an easy problem; 100 M concurrent connections is a smaller number and a much harder one. Say which of your numbers are merely large.
- The pitfall: computing storage and never computing bandwidth or memory. Storage is the cheap one. Egress bandwidth and RAM are where the money and the architecture actually live.
- If a number comes back small, say so and simplify the design. "That's 100 writes a second, so one Postgres primary with a replica handles this for years" is a stronger answer than any distributed store.
Before you move on
- Can you convert "N events per day" to "per second" in your head using the 100,000-seconds-a-day trick?
- Can you compute peak QPS from a DAU figure and a stated peak multiplier, and explain why you size the fleet from peak, not average?
- Can you explain why a "how would this scale" prompt needs both a storage AND a bandwidth calculation?
- Can you name the three most common estimation mistakes — forgetting replication, confusing bits and bytes, sizing from average load — and catch them in your own numbers?
- Can you say, for a given system, which computed number is merely large versus which one is genuinely hard (e.g. 18 TB of metadata versus 100M concurrent sockets)?
- Can you state the 5-year blob storage for the photo example as raw, 3x replicated and erasure-coded (about 55, 165 and 77 PB) and say why the planning figure for one relational primary (20,000 reads/s, 5,000 writes/s) is a starting point rather than a limit?
Sources and further reading
- Latency Numbers Every Programmer Should Know (original list) — the original figures credited to Jeff Dean and Peter Norvig, including the 150 ms transatlantic round trip
- Interactive latency numbers by year (Colin Scott) — the 2020 extrapolation: 1 MB from memory in 3 µs, SSD read 16 µs, disk seek 3 ms
- OpenAI: scaling PostgreSQL — one primary plus many replicas at very high aggregate query rates, so single-primary limits are far above planning figures
- WhatsApp: 1 million is so 2011 — 2.28 million simultaneous connections on one tuned server, 24 CPUs and about 96 GB of RAM
- Redis benchmarks documentation — non-pipelined versus pipelined throughput and the single-threaded command execution caveat
- LinkedIn: benchmarking Kafka on three cheap machines — the throughput numbers behind the per-broker planning figure
Claims in this chapter were checked against these sources in October 2026. Figures marked "planning figure" are rules of thumb, not guarantees.
5 questions drawn from 8, scored out of 5. This is practice: it runs in your browser, saves nothing and does not change what you have marked read.
Finished reading?
0 of 36 chapters read in this series