Skip to the chapter
←System DesignGGroundworkSDSystem Design
System Design/Advanced/A11
31 / 36 written chapters
/

The cover
  1. B1The mental model
  2. B2Client-server basics
  3. B3Vertical vs horizontal
  4. B4Databases in design
  5. B5Caching fundamentals
  6. B6APIs & communication
  7. B7Walkthrough: URL shortener
  1. I1Load balancing in depth
  2. I2CDNs
  3. I3Message queues & async
  4. I4Consistency models
  5. I5Replication
  6. I6Rate limiting & throttling
  7. I7Designing for availability
  8. I8Storage systems
  9. I9Search systems
  10. I10Microservices
  11. I11Security basics
  12. I12Walkthrough: feed/chat
  13. I13Walkthrough: notifications
  1. A1CAP theorem in depth
  2. A2Transactions and isolation
  3. A3Storage engines
  4. A4Sharding at scale
  5. A5Time, ordering and IDs
  6. A6Distributed consensus
  7. A7Batch & stream processing
  8. A8Fault tolerance
  9. A9Observability at scale
  10. A10Release safety
  11. A11Capacity estimation
  12. A12Case studies
  13. A13Walkthrough: key-value store
  14. A14Walkthrough: web crawler
  15. A15Walkthrough: payments
  16. A16Tradeoff thinking

SDA11 · Part 3 · Advanced

Capacity estimation

The whiteboard arithmetic that turns hand-waving into a design — no calculator, about three minutes, out loud.

17 min read2 diagrams8 sections0 exercises
31 of 36

In this chapter

  • Why they make you do arithmetic
  • The rounding conventions that make it tractable
  • The order — always the same eight steps
  • Numbers worth memorizing
  • Worked example 1 — a photo-sharing service

and 3 more

about 17 min
08On this page
  1. Why they make you do arithmetic
  2. The rounding conventions that make it tractable
  3. The order — always the same eight steps
  4. Numbers worth memorizing
  5. Worked example 1 — a photo-sharing service
  6. Worked example 2 — a chat service
  7. How each number cashes out as a design decision
  8. Recognizing it in an unseen problem

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.

QuantityTrue valueUse thisError, and which way
Seconds in a day86,400100,000 = 105Rate estimates come out ~14% low. Irrelevant next to a 3× peak multiplier.
Seconds in a month2,592,0002.5 × 106Under 4% off.
Seconds in a year31,536,0003 × 107~5% low. (The famous mnemonic: π × 107.)
Days in 5 years1,8252,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 / PB210, 220, 230, 240, 250103, 106, 109, 1012, 10157% low at GB, 10% at TB. Say "I'm using powers of ten" once and move on.
Peak-to-average trafficvaries2-3× (10× if event-driven: ticket sales, live sport, New Year)State which one you chose and why.
Fraction of DAU concurrent at peakvaries10-25%Only matters for connection-oriented systems.
Storage replication overheadvaries3× for replicas, 1.4× for erasure codingForgetting 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

1. DAU given or assumed 2. avg req/sec ÷ 100,000 s 3. PEAK req/sec × 2-3 4. storage/day writes × bytes 5. storage / 5 yr × 365 × 5 × copies 6. bandwidth bytes/s → Gbps 7. cache RAM hot set × row size 8. servers peak ÷ per-box
Step 3 sizes the fleet, step 5 chooses the storage engine, step 6 decides whether you need a CDN. Do them in this order: the average becomes the peak, storage per day becomes storage over the retention period, and the peak feeds the server count at the end; skip one and you will be caught out by the interviewer who asks "so how many machines?"

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.

OperationTime (rounded)Anchor
L1 cache reference~1 nsthe 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 reference100 ns100× slower than L1 — this is why cache locality wins
Compress 1 KB~2 µscompression 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 µsultra-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 msyour 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 mswhy random I/O on HDD is a design error, not a tuning problem
Round trip US east to US west~60-70 msthe 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 msNew York to London is about 70 ms
Round trip US east to India / Singapore / Australia~200-230 msthe reason "just put it in one region" fails a global product
ComponentThroughput to assumeNote
Single relational primary (Postgres/MySQL), modern NVMe server, warm cachePlanning figure: ~20,000 simple indexed point reads/s and ~5,000 committed writes/sConservative 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 replicaPlanning figure: another ~20,000 simple reads/s eachReplicas 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 call1,000-5,000 rpsUse 1,000 for sizing. It is conservative and defensible.
nginx / envoy serving static or proxyingPlanning figure: ~50,000 rps per box
Kafka brokerPlanning figure: ~100 MB/s sustained per brokerSequential 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 NIC1.25 / 3.1 GB/sDivide by 8. Bandwidth is quoted in bits, storage in bytes — this is the classic slip.
One commodity server, 202664-128 cores, 256 GB-2 TB RAM, tens of TB NVMeBigger than most candidates assume. Vertical scaling gets you further than the folklore suggests.
ThingBytes
char / boolean / int / bigint or timestamp / UUID1 / 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."
clients 200 M DAU CDN edge 95% hit ratio origin + object store 55 PB raw, ~77 PB coded ~960 Gbps ~48 Gbps the hit ratio is the whole design: at 80% the origin needs ~190 Gbps, at 99% it needs ~10 Gbps — so cache-key design is a capacity decision
The CDN is not there to reduce latency here; it is there because the origin physically cannot emit a terabit per second. Quote the hit ratio as an assumption, because the origin number is entirely a function of it.

How each number cashes out as a design decision

The number you computedWhat it rules outWhat it rules in
60,000 peak reads/secA 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 ratioOptimising for write throughput; normalised schemas with joins on the read pathDenormalised read models, aggressive caching, fan-out-on-write (see the case-studies chapter)
30 TB/day of blobsStoring images in the database. Ever.Object storage + CDN; the DB holds a 500-byte row with a URL
18 TB of metadata over 5 yearsSharding into 100 shards on day oneOne primary + replicas, with a shard key chosen now and applied later
~1 Tbps peak egressServing from origin, single-regionCDN with an explicit hit-ratio target; cache keys designed for hit ratio
100 M concurrent socketsStateless HTTP polling; a stateless gateway tierPersistent connections (~400-500 gateway boxes at 250k each), sticky routing, a socket-location registry, graceful drain on deploy
5 GB routing tableA database lookup on every message deliveryIn-memory table, replicated, rebuilt from connection state on restart
600,000 peak writes/secA relational primary; synchronous cross-region replicationLSM-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

StepQuantityComputationResult
1DAUgiven200,000,000
2Avg feed reads/sec(200M × 10 opens) ÷ 100,000 s20,000/s
3Peak feed reads/sec20,000 × 360,000/s — sizes the fleet
4Blob storage/day20M posters × 1.5 MB30 TB/day
5Blob storage / 5 yr30 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
6Peak bandwidth2 MB/page × 60,000 pages/s × 8 bits/byte~960 Gbps — makes a CDN non-negotiable
7Cache RAM7 days × 20M posts/day × 500 B70 GB — trivial, fits a small Redis tier
8Servers60,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.

✓Practise

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.

A11

Finished reading?

0 of 36 chapters read in this series

→Next stop

  1. A10Previous · A10Release safety and incident response
  2. A11you are here
  3. Next · A12Real-world case studiesSix systems you use every week, one or two interesting decisions each, the bill that came with them, and what has changed since.23 min read

01On this page

8 sections · 0%

  1. 01Why they make you do arithmetic
  2. 02The rounding conventions that make it tractable
  3. 03The order — always the same eight steps
  4. 04Numbers worth memorizing
  5. 05Worked example 1 — a photo-sharing service
  6. 06Worked example 2 — a chat service
  7. 07How each number cashes out as a design decision
  8. 08Recognizing it in an unseen problem

[] chapters · t top