Module 00: Capacity Estimation and Back-of-Envelope Math
Why this matters
Every system-design answer is secretly a sizing argument. "We'll cache it" means nothing until you can say how much — 10 GB fits in one Redis node's memory, 10 TB does not and forces you to shard. "We'll just query the database" is fine at 100 writes/second and a disaster at 100,000. The entire reason interviewers ask you to estimate capacity up front is that the numbers decide the architecture: they tell you whether one machine is enough or you need a fleet, whether data fits in RAM or must live on disk, whether a single region works or you're forced into geo-distribution. Skip the math and every later decision is a guess.
The good news is that nobody expects precision. This is back-of-envelope estimation — you want the right order of magnitude, the right power of ten, not a spreadsheet. Is peak QPS in the hundreds, the thousands, or the millions? Is five-year storage measured in gigabytes, terabytes, or petabytes? Getting that power of ten right is the difference between a design that holds up and one that falls apart the moment the interviewer probes it. This module gives you the handful of numbers worth memorizing, a repeatable estimation recipe (users → requests → bandwidth → storage → memory), and enough practice that you can do it out loud, on a whiteboard, without a calculator.
Concepts
The estimation recipe: from users to infrastructure
Almost every capacity estimate follows the same chain, and doing it in this fixed order keeps you from skipping a step under pressure:
- Users → actions. Start from a given user count (DAU — daily active users) and an assumed action rate. "200M DAU, each posts 2 tweets/day" → 400M writes/day.
- Actions/day → average QPS. Divide by the seconds in a day. The number to memorize: ~100,000 seconds/day (86,400, round to 10⁵). So 400M/day ÷ 10⁵ ≈ 4,000 writes/second average.
- Average → peak QPS. Real traffic is bursty; multiply average by a peak factor of 2–10× (use ~3× unless told otherwise). 4,000 × 3 ≈ 12,000 writes/second peak.
- Reads vs. writes. Most systems are read-heavy. Apply a read:write ratio (100:1 for a social feed, 10:1 for many apps). 4,000 writes → 400,000 reads/second average.
- QPS → bandwidth. Multiply request rate by average payload size.
- Data/day → storage over N years. Multiply per-item size by item rate by the retention window, then add a replication factor.
- Hot set → memory. Estimate what fraction of data is "hot" (often via the 80/20 rule) to size your cache.
Every one of those steps is a single multiply or divide. The skill is doing them in order and not dropping a factor of ten. Visually, the recipe is a funnel that turns one input number (DAU) into every infrastructure sizing you need:
DAU ──× actions/user──► actions/day
│ ÷ 10^5 (sec/day)
▼
avg QPS ──× peak factor──► peak QPS
│ │
× read:write × payload size
▼ ▼
read QPS bandwidth
│
× item_size × retention × replication ──► storage
× 0.2 (hot set) ──────────────────────► cache/memory
The numbers worth memorizing
You can't estimate if you have to derive every constant. Memorize this short list; everything else you compute from it.
- Seconds in a day ≈ 86,400 ≈ 10⁵ (the single most useful one).
- Powers of two → data sizes: 2¹⁰ = 1 thousand (KB), 2²⁰ = 1 million (MB), 2³⁰ = 1 billion (GB), 2⁴⁰ = 1 trillion (TB), 2⁵⁰ = PB. Each step is ~×1000.
- Typical payload sizes: a short text record (tweet, chat message) ~ hundreds of bytes to ~1 KB; a JSON API response ~ 1–10 KB; a photo ~ 200 KB–1 MB; a minute of video ~ tens of MB.
- Char = 1 byte (ASCII/UTF-8 common case); a UUID ~ 16 bytes raw, 36 as a string; a timestamp ~ 8 bytes; a 64-bit id ~ 8 bytes.
- One commodity server, ballpark: tens of thousands of simple requests/sec if CPU-bound and cached; a single SQL database comfortably does thousands of writes/sec, not hundreds of thousands.
- Latency ladder (Jeff Dean's numbers, rounded): L1/L2 cache ~ 1 ns, main memory ~ 100 ns, SSD random read ~ 100 µs (100,000 ns), rotational disk seek ~ 10 ms, same-datacenter round trip ~ 0.5 ms, cross-continent round trip ~ 100+ ms. The load-bearing takeaways: memory is ~1000× faster than SSD, SSD is ~100× faster than a disk seek, and a network hop across the world costs more than a million memory accesses.
Estimating storage and bandwidth
Storage is a rate times a retention window. Write down the per-item size, the items-per-second (or per-day), the retention period, and the replication factor, then multiply:
storage = item_size × item_rate × retention_window × replication_factor
Worked example — a URL shortener storing 100M new URLs/day, each row ~500 bytes, kept 5 years, replicated 3×:
per day = 100M × 500 B = 5 × 10^10 B = 50 GB/day
per 5 yr = 50 GB × 365 × 5 ≈ 91 TB
replicated = 91 TB × 3 ≈ 274 TB → call it ~300 TB
Bandwidth is QPS times payload:
bandwidth = qps × avg_payload_size
If that same shortener serves 400K redirects/sec at ~500 bytes each: 400,000 × 500 B = 2 × 10⁸ B/s = 200 MB/s ≈ 1.6 Gbps of egress. That single number tells you whether one server's NIC can cope (no) and that you need a CDN or load- balanced fleet.
Estimating QPS, servers, and memory
Turn a peak QPS into a server count by dividing by what one server can handle:
servers ≈ peak_qps / per_server_capacity (then add headroom + redundancy)
If peak read QPS is 400,000 and one cache-backed app server does ~20,000 req/sec, you need ~20 servers for load — round up, add redundancy (N+2), and you're provisioning ~24. Never provision for exactly peak: leave headroom for growth, deploys, and failures.
For memory / cache sizing, apply the 80/20 rule — roughly 20% of data serves 80% of requests, so cache the hot 20%:
cache_size ≈ 0.2 × daily_data_touched
If a service reads 100 GB of distinct data per day, caching the hot ~20 GB captures most requests and fits comfortably in a single large Redis node's RAM — recall the cache-aside pattern and hot-key thinking from 05-caching-and- performance. If the hot set were 2 TB instead, no single node holds it and you're into a distributed cache (module 04 of this track).
Sanity checks and orders of magnitude
The point of the exercise isn't the final digit — it's the shape. After every estimate, sanity-check it:
- Does the power of ten feel right? 12,000 writes/sec for a global social network — plausible. 12 writes/sec — too low, you dropped a factor. 12M/sec — too high, that's more than Twitter's real peak; recheck.
- Does it change the architecture? If your storage estimate is 50 GB, a single database is fine and sharding is over-engineering. If it's 500 TB, one box is impossible and sharding is mandatory. State that conclusion — the number exists to drive a decision.
- State your assumptions out loud. "Assuming 200M DAU, 2 posts each, 100:1 read:write, 3× peak" — the interviewer cares far more that your assumptions are explicit and your arithmetic is consistent than whether DAU is really 180M or 220M. Wrong-but-stated beats right-but-hidden.
Reference architecture
The whole point of the math is that each number sizes a box. Here is a generic web-service architecture with every tier annotated by the estimate that determines how big it is — read it as "estimate on the left decides the box on the right":
peak_qps = avg_qps × peak_factor
│
┌────────┐ ┌──────────────────▼─────┐ ┌───────────────────────────┐
│ Client │───►│ Load Balancer │───►│ App server fleet │
│ (many) │ │ (spreads peak QPS │ │ N ≈ peak_qps / │
└────────┘ │ across the fleet) │ │ per_server_capacity │
└─────────────────────────┘ │ (+ N+2 redundancy) │
└──────┬──────────┬──────────┘
cache lookup │ │ cache miss
▼ ▼
┌───────────────┐ ┌───────────────────┐
│ Cache layer │ │ Database │
│ (Redis) │ │ (primary + │
│ size ≈ 0.2 × │ │ read replicas) │
│ daily data │ │ disk ≈ item_size │
│ = hot set │ │ × rate × retention│
└───────────────┘ │ × replication │
└─────────┬──────────┘
large blobs │
(photos/video) ▼
┌──────────────────────────────────────┐
│ Object storage ──► CDN edge │
│ sized by total blob bytes; │
│ egress ≈ qps × avg_payload_size │
└──────────────────────────────────────┘
Component walkthrough:
- Client fleet — the source of the workload. Its size (DAU × actions/user) is the single input number that the whole estimation recipe funnels: DAU → actions/day → QPS.
- Load Balancer — spreads incoming requests across app servers. It has to
absorb peak QPS (
avg_qps × peak_factor, default 3×), which is why the peak factor step of the recipe matters: you size for the burst, not the average. - App server fleet — stateless compute. The number of machines comes straight
from the server-count formula:
peak_qps / per_server_capacity, rounded up, plus N+2 redundancy and growth headroom. This is where "one commodity server handles ~10⁴–10⁵ req/sec" turns a QPS number into a machine count. - Cache layer (Redis) — holds the hot set so most reads never touch the DB.
Sized by the memory / 80-20 math:
cache_size ≈ 0.2 × daily_distinct_data. If that number fits one node's RAM you're done; if not, it forces a distributed cache (module 04). - Database (primary + read replicas) — the durable store. Its disk footprint
is the storage formula:
item_size × item_rate × retention × replication. That number decides single-node vs. sharded, and the read replicas exist because the read:write ratio pushes far more reads than one primary can serve. - Object storage + CDN — for large blobs (photos, video) and static egress.
Sized two ways: total capacity from summed blob bytes, and the bandwidth
formula
qps × avg_payload_size, whose result (e.g. 1.6 Gbps of egress) is what tells you a single NIC can't cope and a CDN is mandatory.
Command reference
Numbers and formulas to memorize. This is your whiteboard cheat sheet.
| Quantity | Value to use | Note |
|---|---|---|
| Seconds per day | ~86,400 ≈ 10⁵ | The single most useful constant |
| Seconds per month | ~2.5 × 10⁶ | 30 × 86,400 |
| KB / MB / GB / TB / PB | 10³ / 10⁶ / 10⁹ / 10¹² / 10¹⁵ | Decimal approx of 2¹⁰·ⁿ |
| Peak factor | 2–10× average (default ~3×) | Traffic is bursty |
| Read:write ratio | 10:1 typical, 100:1 social feed | Most systems read-heavy |
| Char / ASCII byte | 1 byte | |
| 64-bit id / timestamp | 8 bytes | |
| UUID | 16 B raw, 36 B as string | |
| Short text record | ~0.1–1 KB | tweet, chat message |
| Photo / minute of video | ~0.2–1 MB / ~tens of MB | |
| Single SQL DB write ceiling | ~thousands/sec | not hundreds of thousands |
| Cached app server | ~10⁴–10⁵ req/sec | order of magnitude |
| Hot-set fraction (80/20) | ~20% of data serves ~80% of reads | cache sizing |
Latency ladder (rounded, memorize the ratios not the digits):
| Operation | Time | Relative |
|---|---|---|
| L1 cache reference | ~1 ns | 1× |
| Main memory reference | ~100 ns | 100× |
| SSD random read | ~100 µs (10⁵ ns) | ~1,000× memory |
| Same-datacenter round trip | ~0.5 ms | |
| Rotational disk seek | ~10 ms | |
| Cross-continent round trip | ~100+ ms | ~10⁶× memory |
The four formulas:
avg_qps = actions_per_day / 10^5
peak_qps = avg_qps × peak_factor (2–10, default 3)
storage = item_size × item_rate × retention × replication_factor
bandwidth = qps × avg_payload_size
servers = peak_qps / per_server_capacity (round up, add N+2 redundancy)
cache_size = 0.2 × daily_distinct_data_touched
Hands-on exercises
Do these on paper (or a whiteboard) with no calculator — that's the skill. Write your assumptions first, then the arithmetic, then a one-line sanity check.
1. Warm up: QPS from DAU
A photo-sharing app has 500M DAU, and each user uploads 1 photo/day on average. Compute the average upload QPS, then apply a 3× peak factor for peak upload QPS. Then, given a 100:1 read:write (view:upload) ratio, compute peak view QPS. Expected order of magnitude: uploads in the thousands/sec, views in the hundreds-of-thousands/sec.
2. Storage over five years
Each of those photos averages 400 KB, plus a 1 KB metadata row, kept for 5 years, replicated 3×. Estimate total storage. State it in TB or PB and then answer the architectural question: does this fit on one machine, and what does that imply?
3. Bandwidth and the NIC
Using your peak view QPS from exercise 1 and the 400 KB photo size, estimate peak egress bandwidth in GB/s and Gbps. A single server NIC is ~10–25 Gbps. Conclude, in one sentence, what infrastructure this forces (hint: recall CDNs and edge caching from 05-caching-and-performance).
4. Memory / cache sizing
The app serves 100 TB of distinct photos over a typical day but requests follow an 80/20 distribution. Estimate the hot-set size to cache. A large cache node holds ~256 GB RAM. Does the hot set fit in one node, and if not, roughly how many nodes — and what does that tell you about needing module 04's distributed cache?
5. Server count from QPS
Peak view QPS is ~1.5M/sec (use your own number if different). One CDN/cache- backed edge server sustains ~50,000 req/sec. How many edge servers do you need for load alone, and how many after adding N+2 redundancy and 30% growth headroom? Round sensibly.
6. The latency-ladder decision
You have a read path that currently does one rotational-disk seek per request. You're considering moving the hot data to (a) SSD or (b) RAM. Using the latency ladder, state the approximate speedup of each move, and explain which one turns a 10 ms read into a sub-millisecond read. Tie it back to why caching in memory is the highest-leverage change.
7. A write-heavy twist
An IoT platform ingests telemetry from 10M devices, each sending 1 reading every 10 seconds, each reading 100 bytes. Compute sustained write QPS and daily write volume. Then answer: can a single SQL primary absorb this write rate (recall the DB write ceiling), and if not, name the technique from 04-databases-and-data-layer you'd reach for.
8. Diagnose and fix a flawed estimate
A candidate presents this estimate for a chat app. Find every error and redo it correctly.
"We have 50M daily users sending 40 messages each. That's 50M × 40 = 2 billion messages a day. Dividing by the 3,600 seconds in a day gives about 550,000 messages/second average. Peak is the same since chat is steady. Each message is 1 KB, so storage per day is 2 billion × 1 KB = 2 GB. Over 5 years that's about 3.6 TB, so a single database is clearly fine."
Solution
Three concrete errors, one questionable assumption, and a wrong conclusion:
- Wrong seconds/day. They used 3,600 (that's seconds in an hour). It's ~86,400 ≈ 10⁵. Correct average QPS = 2 × 10⁹ / 10⁵ = 20,000 msg/sec, not 550,000. (They were off by ~24× — exactly the hour/day confusion.)
- No peak factor. "Peak is the same since chat is steady" is wrong — chat is very bursty (evenings, events). Apply ~3×: peak ≈ 60,000 msg/sec.
- Storage arithmetic is off by 10⁶. 2 × 10⁹ messages × 1 KB (10³ B) = 2 × 10¹² B = 2 TB/day, not 2 GB. They dropped the KB→byte factor entirely.
- Five-year storage. 2 TB/day × 365 × 5 ≈ 3.65 PB, not 3.6 TB — again off by ~1000 because of the per-day error. With 3× replication, ~11 PB.
- Wrong conclusion. "A single database is clearly fine" follows only from the broken 3.6 TB number. The real ~3.65 PB (11 PB replicated) mandates sharding and tiered/cold storage — the exact opposite decision.
Lesson: a single dropped factor of ten (or here, several) doesn't just make the number wrong — it flips the architecture. Always sanity-check the power of ten against reality before drawing a conclusion.
Independent challenge
No solution given. Using only the recipe and the memorized numbers, produce a complete capacity estimate for a global ride-hailing app — the kind of back-of-envelope pass you'd open a 01-the-system-design-interview-framework session with. Assume 100M DAU, each taking 2 rides/day, and that an active ride sends a GPS location update every 4 seconds for an average 15-minute trip. Estimate: (a) ride-request write QPS and peak; (b) sustained location-update write QPS (this is the scary number — it's not driven by ride count but by concurrent active trips); (c) storage per day if each location point is ~100 bytes and each ride record ~2 KB; (d) five-year storage with 3× replication; and (e) one sentence per number on what architectural decision it forces. Write every assumption down first.
Hint
The location-update rate is the trap and the whole point. Don't multiply total daily rides by updates-per-ride and divide by seconds — that under-counts the sustained load because trips overlap. Instead compute the number of concurrent active trips at peak (rides/day × trip_duration / seconds_in_day, times your peak factor) and multiply by the per-trip update frequency (one every 4 s = 0.25/sec). That concurrent-trips number is what actually hammers your ingestion pipeline, and it's why real systems put location updates on a streaming/queue path (recall background processing from 06-background-processing-and- realtime) instead of straight into a SQL primary.
Common mistakes & troubleshooting
- Seconds-per-day errors. Using 3,600 (an hour) or 24 instead of ~86,400 ≈ 10⁵. This single mistake is the most common source of a 24× or 3,600× error. Memorize 10⁵ and never derive it under pressure.
- Dropping the KB→byte (or MB→byte) factor. "2 billion × 1 KB = 2 GB" — no, it's 2 TB. Track your units explicitly; write the exponent every time.
- Forgetting the peak factor. Provisioning for average QPS guarantees you fall over during the daily peak. Always multiply by 2–10×.
- Ignoring replication and overhead. Raw data × replication factor (usually 3×), plus index/overhead, is the real storage bill — not the raw number.
- Chasing false precision. Grinding out 86,400 × 365 × 4.7 by hand wastes whiteboard time and impresses no one. Round aggressively (10⁵, ×400, ×1000) and keep moving; the order of magnitude is the deliverable.
- Not converting the number into a decision. An estimate that just sits there is useless. Every number must end in "...therefore [one DB is fine / we must shard / we need a CDN / it fits in one cache node]."
- Concurrent-vs-total confusion. For streaming loads (locations, live video, websockets), the load is driven by concurrent sessions, not total daily count. Compute concurrency, not throughput-over-a-day.
Checkpoint quiz
Write down your answer to each question before expanding it — checking without attempting first is the single easiest way to fool yourself into thinking you've learned this.
- What is the approximate number of seconds in a day, rounded to a power of ten, and why is it the single most useful constant in capacity estimation?
- State the full recipe, in order, for going from a DAU figure to a peak read QPS number. Name every step.
- A service does 8.6 billion writes per day. Without a calculator, what's the average write QPS, and what's a reasonable peak?
- Give the storage formula, and explain why leaving out the replication factor understates your real storage bill.
- On the latency ladder, roughly how much faster is a main-memory reference than an SSD random read, and than a rotational-disk seek? Why does that make in-memory caching the highest-leverage optimization?
- Why is stating your assumptions out loud more important than getting DAU exactly right?
- For a live-video or GPS-tracking system, why is concurrent sessions the right load driver rather than total daily sessions?
Answers
- ~86,400, rounded to 10⁵. It converts any per-day action count into an average per-second rate with a single division, which is the backbone of every QPS estimate.
- DAU → actions/day (× actions per user) → average QPS (÷ 10⁵) → peak QPS (× peak factor 2–10) → reads (× read:write ratio). Five steps: users, actions, average, peak, read multiplier.
- 8.6 × 10⁹ / 10⁵ = ~86,000 writes/sec average (≈10⁵). Peak at ~3× ≈ ~250,000–300,000 writes/sec. (This is genuinely large — it implies sharding and a write-optimized path.)
storage = item_size × item_rate × retention_window × replication_factor. Omitting replication (typically ×3) understates the bill by that factor, plus you'd also miss index/overhead — so you'd under-provision disk by 3× or more.- Memory (~100 ns) is ~1,000× faster than SSD (~100 µs) and ~100,000× faster than a disk seek (~10 ms). Moving the hot set from disk/SSD into RAM collapses a multi-millisecond read into a sub-microsecond one, which is why caching in memory beats almost every other single optimization.
- Because the interviewer is evaluating your reasoning, and the arithmetic is only consistent (and checkable) if the assumptions are explicit. A stated assumption that's slightly off still yields a defensible, correct-shaped answer; a hidden one makes the whole estimate unauditable.
- Because those loads are sustained by sessions that overlap in time — the pressure on the system at any instant is the number of sessions currently active, each emitting a steady stream, not the total that started that day. Total-per-day divided by seconds under-counts the real concurrent throughput.
Further reading & sources
- Numbers Every Programmer Should Know (Jeff Dean's latency ladder) - the canonical latency numbers (memory vs. SSD vs. disk seek vs. network) that this module's latency ladder is drawn from.
- System Design Primer — Back-of-the-envelope calculations - the widely-used open-source cheat sheet of powers of two, per-second conversions, and capacity constants.
- Powers of two and data-size units - reference for KB/MB/GB/TB/PB and the decimal-vs-binary approximation used throughout the estimation recipe.
- The Log: What every software engineer should know about real-time data (Jay Kreps) - background on why streaming/queue paths absorb the concurrent-session write loads this module warns about.
- Latency Numbers Every Programmer Should Know — interactive - an interactive version of the latency ladder showing how the numbers scale over hardware generations.
Free PDF notes
Download the notes for each video on this page as a printable PDF, with every diagram and interview questions: SD-D-001: Back-of-the-Envelope Estimation, SD-D-003: How to Estimate RPS, SD-D-004: Peak vs Average Traffic, SD-D-005: Read/Write Ratio, SD-D-006: Storage Estimation, SD-D-007: Bandwidth Estimation, SD-D-008: Cache Sizing, SD-D-009: How Many Servers Do You Need? Capacity, 60% Target & N+2, SD-D-010: Growth Projections, SD-D-011: Back-of-the-Envelope Estimation. Each section in one file: Phase 2, Estimation (PDF).
Next
01-the-system-design-interview-framework — you can now put numbers on a system; next you'll learn the structure that wraps those numbers into a complete whiteboard answer: how to scope the problem with requirements, when to drop in your capacity estimate, how to move from a high-level diagram to a deep-dive, and how to talk through tradeoffs the way interviewers actually score.