Frontend Labs
⋯

Part I — Beginner: Foundations

The building blocks of almost every design, assuming no prior distributed- systems knowledge. By the end of Part I you can estimate load, draw a standard web architecture, design an API, choose a database, add caching, and scale reads.


3. Back-of-the-Envelope Estimation

3.1 Numbers to memorize

Time

1 day   = 86,400 s        ≈ 10^5 s    (use 100k for mental math)
1 month ≈ 2.6M s          ≈ 2.5 * 10^6
1 year  ≈ 31.5M s         ≈ 3 * 10^7

1M requests/day   ≈ 12 req/s
100M requests/day ≈ 1,200 req/s
1B requests/day   ≈ 12,000 req/s

Sizes (powers of two)

2^10 ≈ 1 thousand  → KB      2^30 ≈ 1 billion  → GB
2^20 ≈ 1 million   → MB      2^40 ≈ 1 trillion → TB      2^50 → PB

Latency (order of magnitude; exact values vary with hardware)

L1 cache reference                       ~1 ns
Branch mispredict                        ~5 ns
Main memory reference                    ~100 ns
Compress 1 KB (fast codec)               ~2-10 µs
Read 1 MB sequentially from memory       ~10-250 µs
SSD random read (4 KB)                   ~16-100 µs
Round trip within a datacenter           ~0.5 ms
Read 1 MB sequentially from SSD          ~1 ms
HDD seek                                 ~2-10 ms
Read 1 MB sequentially from HDD          ~5-20 ms
Round trip US East <-> US West           ~60-70 ms
Round trip US <-> Europe                 ~80-150 ms
Round trip US <-> Australia              ~150-200 ms

The ratios matter more than the exact values: memory is ~100× faster than SSD, SSD is ~10-100× faster than HDD for random access, and a cross-continent round trip costs as much as thousands of in-DC RPCs. That last point is why synchronous cross-region calls on the hot path are almost always wrong.

Throughput of a single node (rough, modern hardware)

Component Ballpark per node
Stateless app server (simple JSON API) 1k–10k req/s per core-heavy instance
Redis / Memcached 100k–1M ops/s
Postgres / MySQL (simple indexed reads) 10k–50k QPS; writes 1k–10k TPS (fsync-bound)
Cassandra / ScyllaDB node 10k–100k+ writes/s
Kafka broker hundreds of MB/s; ~1M small msgs/s per cluster is routine
Network NIC 10–100 Gbps

3.2 The estimation recipe

1. Users:      DAU, and actions per user per day
2. QPS:        avg = DAU * actions / 86,400; peak = avg * (2-5x)
3. Storage:    writes/day * object size * retention (* replication factor 3)
4. Bandwidth:  QPS * payload size (ingress and egress separately)
5. Memory:     cache the hot set (often 20% of the daily read volume, Pareto)
6. Machines:   peak QPS / per-node capacity, then add headroom (N+2, ~50-60% target util)

3.3 Worked example: a Twitter-like timeline

Assumptions
  DAU                     = 200M
  Tweets per user per day = 0.5      → 100M tweets/day
  Timeline reads per user = 20/day   → 4B reads/day
  Tweet size              = 300 bytes text + 200 bytes metadata ≈ 500 B
  Media: 10% of tweets have media, avg 500 KB

Write QPS
  100M / 86,400 ≈ 1,160 tweets/s avg; peak 3x ≈ 3,500/s

Read QPS
  4B / 86,400 ≈ 46,000 timeline reads/s avg; peak ≈ 140,000/s
  → read:write ≈ 40:1 → read-optimized design (precompute timelines)

Storage (text)
  100M * 500 B = 50 GB/day → ~18 TB/year → ×3 replication ≈ 55 TB/year
Storage (media)
  10M * 500 KB = 5 TB/day → ~1.8 PB/year → object storage + CDN, not the DB

Egress
  140k reads/s * 20 tweets * 500 B ≈ 1.4 GB/s of text at peak
  (media egress dominates by orders of magnitude → CDN is mandatory)

Timeline cache (fan-out-on-write)
  Store last 800 tweet IDs per active user: 800 * 8 B = 6.4 KB/user
  200M users * 6.4 KB ≈ 1.3 TB → ~a few dozen 64 GB cache nodes (with replicas)

Decisions this forced: a precomputed timeline cache (read-heavy), media in object storage behind a CDN (petabytes), and tweet text in a horizontally scalable store (tens of TB per year). That is the purpose of estimation.

3.4 Estimation mistakes interviewers notice

  • Forgetting peak vs average. Design for peak, and pay for the average using autoscaling.
  • Forgetting the replication factor (×3) and index overhead (often +30–100%).
  • Mixing bits and bytes in bandwidth (a 10 Gbps NIC moves ~1.25 GB/s).
  • Presenting false precision. "About 50k QPS" is better than "46,296 QPS".
  • Not stating which decision the number drives.

3.5 🏗️ Flow: estimation as a decision tree

 Assumptions (DAU, actions/user, object sizes, retention, peak factor)
        │
        ├──▶ Write QPS ──▶ < 5k/s ? ──yes──▶ single relational primary OK
        │                      └──no──▶ sharded SQL / wide-column / log-structured store
        │
        ├──▶ Read QPS ──▶ read:write > 10:1 ? ──yes──▶ cache tier + replicas / precompute
        │
        ├──▶ Storage/yr ──▶ > 10 TB hot ? ──yes──▶ partitioning + tiering (hot/warm/cold)
        │                        └── blobs? ──▶ object store + CDN, metadata only in DB
        │
        ├──▶ Egress ──▶ > 1 Gbps sustained ? ──yes──▶ CDN mandatory; cost is now egress-dominated
        │
        └──▶ Concurrent connections ──▶ > 1M ? ──yes──▶ dedicated connection gateway tier
                                                        (memory per conn × conns per node)

3.6 🌍 In production: real numbers to calibrate against

System Published number What it teaches
Twitter timelines (QCon 2013 talk, "Timelines at Scale") ~300k QPS of timeline reads vs a few thousand tweets/s of writes; home timelines kept in Redis, capped at ~800 entries Read:write of about 100:1 justifies fan-out on write
WhatsApp (2012 blog) ~2 million concurrent TCP connections on a single FreeBSD/Erlang server Connection count, not QPS, can size a chat fleet
Slack + Vitess (2020 blog) ~2.3M QPS at peak (2M reads, 300k writes), median query 2 ms, p99 11 ms What a well-run sharded MySQL fleet delivers
Discord on ScyllaDB (2023 blog) 177 Cassandra nodes → 72 ScyllaDB nodes; p99 reads from 40–125 ms down to 15 ms Storage engine and GC behavior change fleet size by 2–3×
Ticketmaster, Eras Tour presale (2022 statement) ~3.5B system requests, 4× their previous peak, driven heavily by bots Peak estimates must include abusive traffic
Alibaba Singles' Day (2019) ~544k orders per second at peak Flash-sale peaks are 100× normal levels

3.7 ⚠️ Corner cases & deep details

Per-row and per-object overhead is not zero.

Postgres heap tuple header ≈ 23 B (+ alignment padding to 8 B) + 4 B line pointer
A "100-byte row" occupies ≈ 130-140 B on disk, before indexes.
Each B-tree index entry ≈ 16-20 B + key size. 3 secondary indexes can double the footprint.
Free space (fillfactor, MVCC dead tuples before VACUUM) → budget +20-50%.

LSM stores: size-tiered compaction can temporarily need ~2× the data size in free disk.
→ "50% disk full" may already be your real ceiling.

Object storage: small objects are priced per request.
10B objects × $0.005 per 1k PUT = $50k just to write them once → batch small items into larger files.

Things candidates forget to multiply by:

  • Retries and duplicates. At 1% error rate with 3 retries, offered load can rise sharply during incidents, which is exactly when you have the least capacity.
  • Fan-out. One user request → 20 backend calls → 20× internal QPS.
  • Indexes, replicas, backups, snapshots, and logs. The "real" storage is often 5–10× the raw data.
  • Connection memory. WebSocket gateways use tens of KB per connection (buffers, TLS state, app state). 1M connections × 50 KB = 50 GB of RAM.
  • Ephemeral ports. A proxy making outbound connections to one backend IP:port has ~28k–64k source ports. High connection churn (no keep-alive) exhausts them, so connections fail while CPU is idle.
  • Skew. The average shard load is meaningless when the hottest shard has 10× the average under a Zipf distribution. Estimate the hottest key and the hottest shard separately.
  • Diurnal plus event peaks. Daily peak ≈ 2–3× average. Event peaks (sports finals, New Year, launches) can be 10–100× and arrive in seconds.

Generated from real-life-system-design-guide.md · 8 Oct 2026 16:36