Back-of-Envelope Estimation
Why It Matters
Capacity math is step 2 of every HLD ([[SD Interview Framework & Pitfalls]]). Point isn't a precise number — it's justifying architecture. "Writes fit on one Postgres box" vs "writes need sharding + a queue" is decided by one QPS calc. Skip the math → every later decision is a guess. Interviewer watches whether the numbers drive the design, not the arithmetic.
Round hard. 86,400 s/day ≈ 100,000. 1 million ≈ 2^20. Goal is right order of magnitude, fast.
The One Discipline That Prevents 90% of Estimation Failures
The interviewer stops trusting every number the moment one doesn't foot. Two rules:
- Write the exponent explicitly, every time. Not "100M × 365." Write
10⁸ × 365 ≈ 3.65 × 10¹⁰. When multiplying two powers of ten, do the exponents first (add them), then the mantissas —2×10⁷ × 5×10⁶→7+6=13,2×5=10→10¹⁴. Powers of ten are where everyone's error rate spikes. - When you correct any input, re-run every calc that consumed it before moving on. The classic failure: fix "36.5B → 365B" on the board but leave storage at the old "18 TB." One stale number poisons the whole board.
- Smell-test the top-line before building down. 10M tweets/day for global Twitter should smell wrong (real ≈ 500M/day). A 5-second gut check catches a 30× base-number miss before three steps compound it.
Say your numbers back as powers of ten out loud: "ten-to-the-eight per day, times three-six-five, is three-six-five times ten-to-the-ten." The verbal check catches the slip the mental math misses.
Numbers to Memorize
Powers of 10 (QPS / counts)
| Name | Value | Symbol |
|---|---|---|
| Thousand | 10³ | K |
| Million | 10⁶ | M |
| Billion | 10⁹ | B / G |
| Trillion | 10¹² | T |
| Quadrillion | 10¹⁵ | P |
Multiplying/dividing = add/subtract exponents. 10⁸ / 10⁵ = 10³. That's the whole trick for QPS.
Powers of 2 → data size
| Power | Value | Name | Note |
|---|---|---|---|
| 2^10 | ~1 thousand | KB | |
| 2^20 | ~1 million | MB | |
| 2^30 | ~1 billion | GB | |
| 2^32 | 4.3×10⁹ | IPv4 space, unsigned int max | |
| 2^40 | ~1 trillion | TB | |
| 2^50 | ~1 quadrillion | PB | |
| 2^64 | 1.8×10¹⁹ | Snowflake / bigint |
Time → seconds (the QPS denominators)
1 day = 86,400 s ≈ 10^5 s (round to 100k)
1 month ≈ 2.5 million s ≈ 2.5×10^6 s
1 year ≈ 31.5 million s ≈ 3×10^7 s
- X per day → per second: ÷ 10⁵.
100M/day = 10⁸/10⁵ = 1,000/s(precise 1,157 — say the round-down). - X per day → per year: × 3.65×10².
10⁸ × 365 = 3.65×10¹⁰ = 36.5B/year. Per 10yr = 365B. - Peak factor: × 2–3× avg. State it; never design to the average.
Data sizes
| Unit | Bytes | Field | Typical size | |
|---|---|---|---|---|
| 1 char (ASCII) | ~1 B | Bool / small int | 1–4 B | |
| 1 KB | 10³ B | Long / timestamp | 8 B | |
| 1 MB | 10⁶ B | UUID | 16 B | |
| 1 GB | 10⁹ B | Short code (7 char) | 7 B | |
| 1 TB | 10¹² B | Tweet / short text | ~140–280 B | |
| 1 PB | 10¹⁵ B | URL (long) | ~100–500 B (use 400–500 B) |
Latency ladder (Jeff Dean — memorize the ratios, not digits)
| Op | Time |
|---|---|
| L1 cache ref | 0.5 ns |
| Mutex lock/unlock | 25 ns |
| Main memory ref | 100 ns |
| Compress 1 KB | 3 µs |
| SSD random read | 150 µs |
| Send 1 KB over 1 Gbps | 10 µs |
| Read 1 MB sequentially from memory | 250 µs |
| Round trip within datacenter | 500 µs |
| Read 1 MB sequentially from SSD | 1 ms |
| Disk (HDD) seek | 10 ms |
| Read 1 MB from disk | 20 ms |
| Packet round trip CA↔Netherlands | 150 ms |
Takeaways that win points: memory ~100k× faster than disk seek → cache hot data. Cross-continent RTT (150 ms) dwarfs everything → co-locate, don't chat across regions. SSD ~100× faster random read than HDD → why nobody spins disks for OLTP.
The Estimation Recipe
Always the same 5 quantities, in order. Announce each subtotal. If you correct step 1, re-do steps 2–4.
- DAU → QPS.
QPS_avg = (DAU × actions/user/day) / 86,400. ThenQPS_peak ≈ 2–3 × QPS_avg. - Read:write ratio. State it explicitly (100:1 feed, 1:1 chat). Drives whether you optimize reads (cache/replicas) or writes (queue/shard).
- Storage = objects/day × size/object × retention. Multiply out to 5 years for the "do we shard" answer.
- Bandwidth = QPS × payload size. Split ingress vs egress; egress is what CDN offloads. Bitrate is bits, storage is bytes — the 8× trap lives here.
- Memory for cache. 80/20 rule — cache the hot 20%.
cache_size = 0.2 × hot_key_count × object_size. Sanity-check vs RAM per node.
Base62 Keyspace (URL shortener / ID length)
| Length | Value | ~Power |
|---|---|---|
| 62⁵ | 916 M | ~10⁹ |
| 62⁶ | 56.8 B | ~5.7×10¹⁰ |
| 62⁷ | 3.52 T | ~3.5×10¹² |
| 62⁸ | 218 T | ~2.2×10¹⁴ |
Pick length so keyspace ≫ total records over retention. 62⁷ (3.5T) vs 365B needed → ~10× headroom → 7 chars. 62⁶ (57B) < 365B → 6 fails.
Worked Example 1 — Twitter-scale Feed
Given: 300M DAU, 2 tweets/day/user, reads timeline 50×/day, tweet ≈ 1 KB (text + metadata), 5-year retention.
# 1. QPS
writes/day = 300M × 2 = 600M
reads/day = 300M × 50 = 15B
write QPS_avg = 600M / 86,400 ≈ 7,000
read QPS_avg = 15B / 86,400 ≈ 170,000
peak read QPS ≈ 3 × 170k ≈ 500,000
# 2. Ratio
read:write ≈ 25:1 → read-heavy → fan-out + cache, replicas for reads
# 3. Storage
writes/day × size = 600M × 1 KB = 600 GB/day
5-year = 600 GB × 365 × 5 ≈ 1.1 PB → must shard, cold storage tiering
# 4. Bandwidth
read egress = 170k QPS × 1 KB ≈ 170 MB/s ≈ 1.4 Gbps steady → CDN/edge cache
# 5. Cache (hot 20% of reads)
0.2 × 15B reads × 1 KB = 3 TB hot set → distributed Redis cluster, not one box
Design conclusions the numbers forced: read-heavy 25:1 → precompute timelines (fan-out on write) + heavy caching; 1.1 PB → shard by user_id, tier old tweets to blob storage; 3 TB hot set → Redis cluster, sharded, not a single instance.
Worked Example 2 — URL Shortener @ 100M writes/day
TRAFFIC
Writes: 100M/day = 10⁸ / 10⁵ s = 1,000/s (precise 1,157; peak ×3 ≈ 3K/s)
Reads: 100:1 = 10¹⁰/day = 10⁵/s = 100,000/s (peak ×3 ≈ 300K/s)
→ All design pressure is on the READ path. Say this sentence.
RECORDS
Per year: 10⁸ × 365 = 3.65 × 10¹⁰ = 36.5 B/year
Per 10yr: × 10 = 3.65 × 10¹¹ = 365 B ← the number to get right
CODE LENGTH (base62)
Need > 365B codes.
62⁶ = 57B < 365B → 6 FAILS
62⁷ = 3.5T / 365B ≈ 10× headroom → 7 chars ✅
STORAGE
365 × 10⁹ records × 500 B = 1.8 × 10¹⁴ B = 182 TB
(small enough to fit on a handful of nodes → shard for throughput, not capacity)
BANDWIDTH
Read: 10⁵/s × 500 B = 5 × 10⁷ = 50 MB/s (trivial)
Write: 10³/s × 500 B = 5 × 10⁵ = 500 KB/s (trivial)
CACHE (Pareto 80/20)
Cache hot code→URL only (~400 B, drop metadata).
Few hundred M hot entries × 400 B ≈ 150–200 GB Redis, cache-aside + LRU.
Note: canonical [[Design a URL Shortener]] uses a 10M/day assumption (→ 9 TB / 5 yr); this example uses 100M/day. Both are internally consistent — the point is the method. Always restate the assumption you picked.
Availability — The Nines
| Availability | Downtime / year | Downtime / day |
|---|---|---|
| 99% | 3.65 days | 14.4 min |
| 99.9% ("three nines") | 8.76 hours | 1.44 min |
| 99.99% ("four nines") | 52.6 min | 8.6 s |
| 99.999% ("five nines") | 5.26 min | 0.86 s |
Sanity-Check Anchors
Ballpark ceilings to catch nonsense answers:
| Resource | Rough single-node ceiling |
|---|---|
| Postgres/MySQL writes | ~10k simple writes/s per node |
| Redis ops | ~100k ops/s per instance |
| Single server RAM | 64–256 GB typical |
| NIC bandwidth | 10 Gbps ≈ 1.25 GB/s |
| SSD sequential read | ~500 MB/s–3 GB/s |
| Kafka partition | ~10 MB/s or ~10k msg/s |
If your calc says "1 Postgres node does 500k writes/s," you rounded wrong or need sharding.
Interview Drill
Q: You estimate 500k peak read QPS. Walk me from that number to a concrete component decision. A: 500k QPS × 1 KB ≈ 500 MB/s egress — one NIC (10 Gbps ≈ 1.25 GB/s) survives but leaves no headroom, and one DB node (~10k reads/s) is 50× short. So: read replicas alone won't cut it (need ~50) → cache in front sized to the hot set, serve the 80% hit rate from Redis, and only the ~100k QPS miss traffic touches replicas. The QPS number directly sized both the cache tier and the replica count.
Q: When do you skip the estimation? A: Never skip it, but keep it to 2 minutes. Even a rough calc that says "this fits on one box" is a result — it tells you not to over-engineer. The mistake is silent hand-waving, not spending too long.
Self-Drill (redo cold, under 4 min each, exponents written out)
- Twitter feed: 500M DAU, 2 tweets/day, each read 100×. Tweets/s? Reads/s? Storage/year at 300 B/tweet?
- Chat app: 50M DAU, 40 messages/user/day, 100 B/message. Messages/s at peak? Storage/year?
- Video platform: 1M videos/day, avg 100 MB each. Storage/day? /year? Egress if each watched 1000× at 5 MB streamed?
- Rate limiter: 1B requests/day across the fleet. Requests/s? 16 B/counter × 100M users → memory?
- URL shortener redo: the Worked Example 2 numbers from scratch, no peeking. Check every power of ten.
Grading rule (self): any single 10× slip = fail the drill, redo it. That's the whole point.
Cross-links
[[SD Interview Framework & Pitfalls]] · [[Core Vocabulary & Quality Pillars]] · [[Latency vs Throughput]] · [[Caching & Redis]] · [[Database Replication & Sharding]] · [[News Feed - Twitter Feed]] · [[Design a URL Shortener]] · [[Design a Unique ID Generator]] · [[Design a Distributed Key-Value Store]] · [[Rate Limiter]]