system_design / design framework / 02_capacity_estimation.md

Capacity Estimation — Back-of-Envelope Math

5 interview angles 5 min read source

Capacity Estimation — Back-of-Envelope Math

The 3-5 minute phase that turns “design a system” into “design a system at this scale.” You’re not aiming for precision — you’re deriving whether you need one server or a thousand, one database or a sharded fleet.

The numbers to memorize

Round everything. These are the anchors:

Quantity Round to
Seconds in a day ~100,000 (actually 86,400)
Seconds in a month ~2.5 million
1 KB 10³ bytes
1 MB 10⁶
1 GB 10⁹
1 TB 10¹²
Char / small field ~1-10 bytes
A typical JSON record ~1 KB
A small image ~100 KB-1 MB
A row in Postgres ~hundreds of bytes-few KB

The four estimates

1. QPS (queries per second)

QPS = DAU × actions_per_user_per_day ÷ seconds_per_day
peak_QPS = QPS × peak_factor   (peak_factor ≈ 2-3)

Example — 10M DAU, each does 10 reads + 1 write per day:

reads:  10M × 10 ÷ 100k  = 1,000 QPS average  → ~2-3k peak
writes: 10M × 1  ÷ 100k  = 100 QPS average    → ~200-300 peak

That’s a single beefy database for writes, a cache + a few read replicas for reads. Not a sharding problem yet — and saying that is the insight.

2. Storage

storage_per_day = items_per_day × bytes_per_item
total_storage   = storage_per_day × retention_days

Example — 1M new posts/day, ~1 KB each, kept forever:

per day:  1M × 1 KB = 1 GB/day
per year: 1 GB × 365 ≈ 365 GB/year
5 years:  ~2 TB

2 TB fits on one machine. If it were 1 GB per second, you’d be reasoning about a partitioned store. The number tells you which conversation to have.

3. Bandwidth

bandwidth = QPS × payload_size

Example — 3k read QPS, 5 KB response each:

3,000 × 5 KB = 15 MB/s outbound

Modest. If responses were 5 MB (video), it’d be 15 GB/s and the design is now about CDN and egress cost.

4. Memory (for caching)

cache_size = items_to_cache × bytes_per_item

Example — cache the hottest 20% of 100M items, 1 KB each:

20M × 1 KB = 20 GB

20 GB fits in one large Redis node. 2 TB doesn’t — that’s a Redis cluster. Again: the number picks the architecture.

The read:write ratio

Often the single most design-shaping number. Consumer apps are typically 10:1 to 100:1 read:write.

  • Very read-heavy → aggressive caching, read replicas, denormalization, fan-out-on-write.
  • Write-heavy → queue to absorb spikes, partition the write path, fan-out-on-read.

State it explicitly: “this is ~50:1 read:write, so I’ll optimize the read path with a cache and replicas, and the write path can be simple.”

Worked example — a URL shortener

Requirements: 100M new URLs/month, 10:1 read:write (people click more than they create).

Writes:
  100M / month ÷ 2.5M sec = 40 writes/sec average → ~100 peak

Reads:
  40 × 10 = 400 reads/sec average → ~1,000 peak

Storage:
  100M URLs/month × 12 months × 5 years = 6B URLs
  per URL: short_code(7B) + long_url(~100B) + metadata(~100B) ≈ 500 B
  6B × 500 B = 3 TB over 5 years

Bandwidth:
  reads return a 302 (tiny) → negligible
  writes ~200 B each × 100/s → trivial

Cache:
  hot 20% of URLs: 1.2B × 500 B = 600 GB → a Redis cluster, or cache only the truly hot tail

Conclusion you’d state: “Write QPS is low — a single primary handles it. Reads are 1k peak — a cache absorbs most. Storage is 3 TB over 5 years — fits on one machine with room, but I’d plan partitioning by short_code prefix for headroom. Nothing here forces exotic infrastructure.”

That paragraph — derived from arithmetic — is worth more than any diagram.

Estimation discipline

  • Round hard, round early. 86,400 → 100,000. 365 → 400 if it helps. Note the direction.
  • One significant figure is fine. You’re choosing between “1 server” and “100 servers,” not “37 vs 41.”
  • State assumptions. “Assume 10M DAU and 10 reads each” — the interviewer corrects you if it matters, and now your math is anchored.
  • Do it out loud. The arithmetic is the artifact being scored, not the final number.
  • Sanity-check the result. “3 TB over 5 years” — does that feel right for a URL shortener? Yes. “3 PB”? You made an arithmetic error; find it.

When the number changes the design

If the estimate says… The design becomes…
< ~5k write QPS, < few TB single primary DB, maybe read replicas — don’t shard
10k+ write QPS or 10+ TB partitioned/sharded store, or DynamoDB
read:write > 20:1 cache + replicas + denormalization is the main effort
bandwidth in GB/s CDN, egress cost becomes a first-class concern
cache working set > one node’s RAM Redis cluster, or cache only the hot tail
spiky writes queue between API and DB to absorb the spike

The whole point of the phase: let the arithmetic pick the architecture, then justify the architecture by pointing back at the arithmetic.

Interview angle

  • “Estimate the QPS for [system].” — DAU × actions-per-user-per-day ÷ ~100k seconds, then ×2-3 for peak. Say the assumptions out loud; round aggressively.
  • “How much storage will this need?” — items/day × bytes/item × retention. Then sanity-check the magnitude — TB vs PB changes everything.
  • “Why does the read:write ratio matter?” — it decides where the engineering effort goes. Very read-heavy → caching, replicas, denormalization, fan-out-on-write. Write-heavy → queues, partitioned writes, fan-out-on-read.
  • “Your estimate came out to X — so what?” — that’s the real question. The number must drive a decision: “40 write QPS means one primary suffices — I won’t shard,” or “15 GB/s bandwidth means this is a CDN problem.” An estimate with no consequence is wasted time.
  • “You don’t know the exact numbers.” — that’s expected. State a reasonable assumption, do the arithmetic on it, and note that the interviewer can adjust the input. The method is what’s scored.