- Back-of-the-envelope estimation = quick, rounded arithmetic that tells you the order of magnitude of load, storage, bandwidth and hardware, so you can justify design decisions.
- Memorise a few anchors: 1 day ≈ 86,400 s ≈ 105 s; 1M/day ≈ 12/s; 1 PB/day ≈ 12 GB/s ≈ 93 Gbps; powers of two (210 ≈ 103); and latency numbers (memory ~100 ns, same-DC round trip ~0.5 ms, cross-continent ~150 ms).
- Method: assumptions → rates (QPS) → sizes (storage, bandwidth) → resources (servers, shards, cache nodes) → sanity check. Always compute average and peak (2–3×).
- Instagram under our assumptions: ~1.2K posts/s, ~116K feed reads/s (~350K peak), ~1.1M API req/s peak, ~580 TB/day new media (~212 PB/year logical), ~85 PB/day egress (~8 Tbps) mostly served by the CDN, ~9 TB of cache, ~1.5 GB/s into Kafka.
- The numbers are the argument: they prove you need a CDN, object storage, sharding, caching and async fan-out.
1. The problem: why estimate at all?
Should Instagram's feed be served from the database or from a cache? Will one PostgreSQL server hold all the posts? Do we need a CDN? You cannot answer any of these by intuition alone. "A lot of users" might mean 1,000 requests per second (one server is fine) or 1,000,000 (you need thousands of servers and a completely different design). Estimation turns vague scale into numbers you can reason with — in two to five minutes, with mental arithmetic.
Estimates are useful precisely because they are rough. Nobody cares whether storage is 580 TB/day or 610 TB/day; what matters is that it's "hundreds of terabytes per day", which immediately means "not in a relational database, use object storage", and "over 200 petabytes per year", which means "storage cost and tiering are first-class concerns". Getting the exponent right is the whole game; the leading digit is a bonus.
Real engineers do this constantly: capacity planning before a launch, checking whether a proposed design can possibly meet its latency target, sanity-checking a cloud bill. Interviewers use it to see whether you can connect requirements to architecture with evidence.
2. The toolkit: numbers worth memorising
2.1 Powers of two (and ten)
Computers count in powers of two; humans in powers of ten. The happy coincidence 210 = 1,024 ≈ 103 lets you switch freely between them with ~2–10% error — negligible for estimation.
| Power of 2 | Exact value | ≈ Power of 10 | Name | Where you meet it |
|---|---|---|---|---|
| 28 | 256 | — | 1 byte holds 256 values | A byte; small enums |
| 210 | 1,024 | 103 (thousand) | 1 KB (KiB) | A short JSON object; a tweet-sized record |
| 216 | 65,536 | ~6.5 × 104 | — | TCP port range; 16-bit counters overflow |
| 220 | 1,048,576 | 106 (million) | 1 MB (MiB) | A photo |
| 230 | ~1.07 billion | 109 (billion) | 1 GB (GiB) | A movie; RAM per process |
| 231 | ~2.1 billion | 2 × 109 | — | Max signed 32-bit int — fewer than Instagram's ~2B users! IDs must be 64-bit |
| 232 | ~4.3 billion | 4 × 109 | — | IPv4 address space; unsigned 32-bit int |
| 240 | ~1.1 trillion | 1012 (trillion) | 1 TB (TiB) | A large SSD; a DB shard |
| 250 | ~1.13 × 1015 | 1015 (quadrillion) | 1 PB (PiB) | A day of Instagram-scale media egress is tens of PB |
| 260 | ~1.15 × 1018 | 1018 | 1 EB (EiB) | Multi-year media archive of a giant platform |
| 263 | ~9.2 × 1018 | ~1019 | — | Max signed 64-bit int — room for Snowflake-style IDs (ID Generation) |
2.2 Handy conversions
| Fact | Value | Shortcut |
|---|---|---|
| Seconds per day | 86,400 | ≈ 105 (overestimates by ~16%, so QPS comes out ~14% low — fine, or use 86,400 when precision matters) |
| Seconds per month | ~2.6 million | ≈ 2.5 × 106 |
| Seconds per year | ~31.5 million | ≈ π × 107 ≈ 3 × 107 |
| 1 million per day | ≈ 11.6 per second | 1M/day ≈ 12/s |
| 1 billion per day | ≈ 11,574 per second | 1B/day ≈ 12K/s |
| Bits vs bytes | 1 byte = 8 bits | Network in bits (Gbps), storage in bytes (GB) |
| 1 Gbps | 125 MB/s | ≈ 0.1 GB/s |
| 1 TB/day | ≈ 11.6 MB/s | ≈ 93 Mbps |
| 1 PB/day | ≈ 11.6 GB/s | ≈ 93 Gbps |
| Peak vs average | Depends on daily curve | peak ≈ 2–3 × average (use 3× for safety; viral events more) |
| Concurrent users | Depends on session length | ≈ DAU × (avg minutes online/day ÷ 1,440) |
2.3 Latency numbers every programmer should know
This famous table (popularised by Jeff Dean and Peter Norvig) gives the cost of basic operations. Exact values vary by hardware generation — modern NVMe SSDs and memory bandwidth have improved several of them — but the ratios are what matter: memory is ~1,000× faster than SSD random reads, and the same data centre is ~300× closer than another continent.
| Operation | Classic latency | In µs / ms | Lesson for design |
|---|---|---|---|
| L1 cache reference | 0.5 ns | CPU caches are effectively free | |
| Branch mispredict | 5 ns | ||
| L2 cache reference | 7 ns | ||
| Mutex lock/unlock | 25 ns | Contention, not the lock itself, is the cost | |
| Main memory reference | 100 ns | 0.1 µs | RAM is the fast tier → caches (Redis) |
| Compress 1 KB (Snappy/Zippy) | ~3 µs | 3 µs | Compression is cheap vs network |
| Send 1 KB over 1 Gbps network | 10 µs | 10 µs | Bandwidth rarely the bottleneck for small payloads |
| Read 4 KB randomly from SSD | ~150 µs (NVMe: ~20–100 µs) | 0.15 ms | SSD random reads OK; batch them |
| Read 1 MB sequentially from memory | 250 µs (modern: tens of µs) | 0.25 ms | Sequential is king |
| Round trip within same data centre | 500 µs | 0.5 ms | Each service hop costs ~0.5–1 ms → limit chatty calls |
| Read 1 MB sequentially from SSD | 1 ms (NVMe: ~0.2 ms) | 1 ms | |
| HDD disk seek | 10 ms | 10 ms | Avoid random I/O on spinning disks; log-structured storage |
| Read 1 MB sequentially from HDD | 20 ms | 20 ms | Cheap bulk storage (cold media tier) |
| Packet round trip California → Netherlands → California | 150 ms | 150 ms | Physics: put data near users (CDN, regions) |
A few practical system-level numbers to add to the classic list (orders of magnitude, assume rather than quote):
- Redis/Memcached GET inside a data centre: ~0.2–1 ms (mostly network). One node: ~100K+ simple ops/s.
- Indexed lookup in a well-tuned SQL database (hot in buffer cache): ~1–5 ms; a single primary handles roughly 5K–20K writes/s depending on hardware and row size.
- Cassandra-style node: ~10K–50K writes/s; comfortable data per node ~1–2 TB (to keep compaction and repair manageable).
- TCP + TLS 1.3 handshake to a server 100 ms away: ~2 round trips ≈ 200 ms before the first byte — which is why connection reuse and edge termination matter (Networking).
- A modern server NIC: 10–100 Gbps. A Kafka broker: ~100 MB/s of sustained produce traffic per broker is a conservative planning number.
HUMAN-SCALE VERSION: multiply every latency by 2 billion (so L1 = 1 second) L1 cache reference ............ 0.5 ns → 1 second (a heartbeat) Main memory reference ......... 100 ns → 3.3 minutes (make a coffee) SSD random read 4 KB .......... 150 µs → 3.5 days (a long weekend) Same-datacenter round trip .... 500 µs → 11.6 days (a holiday) HDD seek ...................... 10 ms → 7.6 months (a pregnancy, almost) California ⇄ Netherlands ...... 150 ms → 9.5 years (primary school) → Every network hop or disk access is an eternity to a CPU. → That is why a feed request that does 20 sequential DB queries is slow, and why we pre-compute timelines and keep them in RAM.
3. The estimation method
- State assumptions explicitly and round them to friendly numbers (500M not 487M). Write them on the board.
- Convert per-day counts into per-second rates, separately for reads and writes. Multiply by a peak factor (2–3×).
- Multiply counts by sizes to get storage (per day, per year, over the retention period) and bandwidth (in and out). Remember replication and multiple renditions.
- Divide by per-machine capacity to get server, shard and cache-node counts. Add headroom (target ~60–70% utilisation) and redundancy (survive losing a zone).
- Sanity-check and, most importantly, say what the number means for the design.
4. Full worked example: Instagram
We now estimate Instagram end-to-end. All inputs are assumptions for design purposes (consistent with the Requirements lesson), not official statistics. Follow along with a pen — the point is the method.
4.1 Assumptions
| Input | Assumption |
|---|---|
| Users | 2B MAU, 500M DAU |
| Posts | 100M/day: 85M photo posts, 15M video posts (carousels folded into the average size) |
| Stories | 200M/day |
| Feed page loads | 20 per DAU per day (each page ≈ 10 posts) |
| Profile views, Stories-tray loads | 10 each per DAU per day |
| Likes / comments | 5B/day / 500M/day (10 likes, 1 comment per DAU) |
| Follows | 100M/day; average ~200 followees per user |
| Search queries | 1B/day (2 per DAU) |
| DMs | 2B messages/day |
| Media sizes | photo upload 1 MB + renditions 0.5 MB; video upload 15 MB + renditions 15 MB; story ~1.5 MB |
| Media consumed | per DAU per day: ~100 images × 200 KB, ~30 videos × 5 MB (includes Stories and Reels views) |
| Peak factor | 3× average |
4.2 Requests per second (QPS)
Rule: QPS = per-day count ÷ 86,400. Using "1B/day ≈ 12K/s":
| Operation | Per day | Average QPS | Peak QPS (3×) | Type |
|---|---|---|---|---|
| Feed page loads | 500M × 20 = 10B | ~116K | ~350K | Read |
| Profile views | 5B | ~58K | ~174K | Read |
| Stories tray loads | 5B | ~58K | ~174K | Read |
| Comment list reads | 2B | ~23K | ~70K | Read |
| Search queries | 1B | ~12K | ~35K | Read |
| Total reads | 23B | ~267K | ~800K | |
| Likes | 5B | ~58K | ~174K | Write |
| DMs sent | 2B | ~23K | ~70K | Write |
| Comments | 500M | ~5.8K | ~17K | Write |
| Stories posted | 200M | ~2.3K | ~7K | Write |
| Posts | 100M | ~1.2K | ~3.5K | Write |
| Follows | 100M | ~1.2K | ~3.5K | Write |
| Total writes | ~7.9B | ~91K | ~275K | |
| All API requests | ~31B | ~360K | ~1.1M |
What it means:
- Post creation (~1.2K/s) is tiny. The upload service is not the scaling challenge; what happens after a post is created is.
- At the API level, reads:writes ≈ 3:1 — because likes are frequent writes. But at the content level: 10B feed pages × 10 posts = 100B post impressions/day vs 100M posts created → ~1,000:1. The feed read path dominates and must be served from memory.
- ~1.1M requests/s at peak means thousands of stateless app servers behind load balancers.
- Likes at ~174K/s peak are a serious write path: write-optimised store plus asynchronous counters (Likes & Comments).
4.3 Fan-out write amplification
With push-based fan-out (News Feed), every post is inserted into each follower's timeline:
timeline inserts/day = 100M posts × 200 followers (avg) = 2 × 10^10 = 20B/day
average = 20B / 86,400 ≈ 231K inserts/s
peak ≈ 700K inserts/s
Optimisation: only fan out to followers active in the last ~30 days.
If ~25% of edges point to recently active users → ~5B/day ≈ 58K/s average.
Celebrities (say >1M followers) are excluded and pulled at read time —
one 500M-follower post would otherwise be 500M inserts on its own.
So each 1 post/s of writes becomes ~200 timeline writes/s — the "small" write rate is amplified 200× inside the system.
4.4 Media storage
Photos: 85M/day × (1 MB original + 0.5 MB renditions) = 85M × 1.5 MB = 127.5 TB/day
Videos: 15M/day × (15 MB original + 15 MB renditions) = 15M × 30 MB = 450 TB/day
Total posts media ≈ 580 TB/day (logical)
Per year: 580 TB × 365 ≈ 212 PB/year (logical, one copy)
Replicated: × 3 copies ≈ 635 PB/year (classic 3× replication)
— or with erasure coding (~1.5× overhead, as large blob stores use) ≈ 318 PB/year raw
5 years, flat volume: 212 PB × 5 ≈ 1.06 EB logical → ~1.6 EB (EC) … ~3.2 EB (3×)
5 years, +20% growth/yr: 212 PB × (1 + 1.2 + 1.44 + 1.73 + 2.07) = 212 × 7.44
≈ 1.6 EB logical → ~2.4 EB (EC) … ~4.7 EB (3×)
Stories: 200M × (1.5 MB + 0.5 MB renditions) ≈ 400 TB/day, but expire after 24 h
→ a rolling ~400 TB hot footprint (× replication), unless archived.
What it means: hundreds of PB per year is far beyond any database — media must live in object storage, with only keys in the metadata DB. Video is ~15% of posts but ~78% of bytes, so video codec efficiency and rendition choices dominate storage cost. Old media is rarely viewed → move it to cheaper "cold" tiers; this one decision changes the storage bill more than anything else.
4.5 Metadata storage
| Data | Row size (assume) | Volume | Per day | Per year (logical) |
|---|---|---|---|---|
| Posts | ~1 KB (ids, caption ~200 B, media keys, location, timestamps, indexes) | 100M/day | 100 GB | ~37 TB |
| Likes | ~50 B (post_id 8 + user_id 8 + timestamp 8 + overhead) | 5B/day | 250 GB | ~91 TB |
| Comments | ~300 B | 500M/day | 150 GB | ~55 TB |
| DMs | ~200 B (text messages; media goes to object storage) | 2B/day | 400 GB | ~146 TB |
| Follow graph | ~30 B per edge, stored in both directions | 2B users × 200 = 400B edges | — | ~24 TB total (not per year) |
| Users | ~1 KB (+ indexes ≈ 2 KB) | 2B | — | ~2–4 TB total |
| Total growth | ~0.9 TB/day | ~330 TB/year → ~1 PB/year with 3× replication |
What it means: metadata is ~650× smaller than media but still far too big for one machine (a single database server comfortably holds ~1–2 TB of hot data). Over 5 years the posts+likes+comments set reaches ~0.9 PB logical → it must be sharded across hundreds of nodes (see section 4.10). Notice that likes outweigh posts: small rows × huge counts add up.
4.6 Bandwidth: ingress and egress
INGRESS (uploads)
posts: 85M × 1 MB + 15M × 15 MB = 85 TB + 225 TB = 310 TB/day
stories: 200M × 1.5 MB = 300 TB/day
total ≈ 610 TB/day → 610 × 10^12 B / 86,400 s ≈ 7 GB/s ≈ 56 Gbps avg (~170 Gbps peak)
EGRESS (media views)
images: 500M DAU × 100 × 200 KB = 10 PB/day
videos: 500M DAU × 30 × 5 MB = 75 PB/day
total ≈ 85 PB/day → 85 × 10^15 / 86,400 ≈ 984 GB/s ≈ 7.9 Tbps avg (~24 Tbps peak)
API (JSON) egress
10B feed pages × ~20 KB = 200 TB/day ≈ 2.3 GB/s ≈ 19 Gbps (~0.2% of media egress)
Egress : ingress ≈ 85 PB : 0.61 PB ≈ 140 : 1
What it means: ~8 Tbps average (~24 Tbps peak) of media cannot be served from a handful of data centres — it needs a globally distributed CDN. API traffic is a rounding error by comparison, which is why the API path and the media path are designed separately.
4.7 CDN vs origin traffic
The CDN absorbs most egress; only cache misses reach object storage (the origin):
| CDN cache hit ratio | Origin egress per day | Origin bandwidth | Reduction vs no CDN |
|---|---|---|---|
| 90% | 8.5 PB | ~98 GB/s ≈ 790 Gbps | 10× |
| 95% | 4.25 PB | ~49 GB/s ≈ 394 Gbps | 20× |
| 99% | 0.85 PB | ~9.8 GB/s ≈ 79 Gbps | 100× |
How many edge servers? If one edge cache server can serve ~40 Gbps of real traffic, peak ~24 Tbps needs at least ~600 servers — and in practice many more, because traffic must be served from hundreds of locations near users, each sized for its local peak plus failover. That's why at this scale companies either buy from the largest CDN providers or, like Meta, build their own edge network.
4.8 Cache memory sizing (the 80/20 rule)
The Pareto (80/20) rule says ~20% of items receive ~80% of requests. So caching the hottest ~20% of the data gives a high hit ratio at a fraction of the memory. There are two ways to size a cache; the second is more reliable.
(a) The classic interview formula — and its trap:
cache ≈ 20% × (read requests/day × response size)
= 0.2 × 10B feed pages × 20 KB = 40 TB ← overestimate!
This counts the same popular post millions of times. Caches store distinct objects, so size by distinct hot objects instead.
(b) Bottom-up, per data structure:
| Cached data | Calculation | Memory |
|---|---|---|
| Feed timelines (post IDs + scores) for DAU | 500M users × 500 entries × 16 B = 4 TB; × ~2 for data-structure overhead | ~8 TB |
| Hot post metadata (80/20) | ~1B distinct posts viewed/day × 1 KB = 1 TB; cache hottest 20% | ~200 GB |
| User profiles of DAU | 500M × 1 KB | ~500 GB |
| Like/comment counters for hot posts | 1B posts × ~50 B (key + 2 counters + overhead) | ~50 GB |
| Sessions / auth tokens | 500M × 200 B | ~100 GB |
| Total | ~9 TB |
Nodes by memory: 9 TB / ~50 GB usable per node (on a 64 GB box) ≈ 180 primaries
Nodes by throughput: feed hydration ≈ 350K pages/s × ~20 lookups = 7M ops/s (peak)
+ fan-out inserts ~0.7M/s ≈ 8M ops/s ÷ ~100K ops/s per node ≈ 80 nodes
→ memory is the binding constraint: ~180 primaries, ×2 with one replica each ≈ 360 cache nodes
What it means: the entire hot working set fits in a few hundred RAM-heavy machines — which is why serving the feed from Redis is feasible at all. Note the timelines dominate; capping them (e.g. 500 entries, older items fetched on demand) is a key cost lever.
4.9 Kafka event throughput
Every domain action publishes an event to Kafka; clients also emit analytics events (impressions, scrolls, video watch time) that feed ranking models.
DOMAIN EVENTS (post, story, like, comment, follow, DM events)
≈ total writes ≈ 91K events/s avg (~275K/s peak) × ~1 KB ≈ 91 MB/s avg (~275 MB/s peak)
ANALYTICS / CLIENT EVENTS
500M DAU × ~500 events/day = 250B events/day ≈ 2.9M events/s × ~500 B ≈ 1.45 GB/s avg
peak ≈ 4.3 GB/s
TOTAL produce ≈ 1.5 GB/s avg, ~4.6 GB/s peak
With replication factor 3, brokers write ≈ 4.6 GB/s avg, ~14 GB/s peak to disk.
Brokers: ~14 GB/s ÷ ~100 MB/s per broker (conservative) ≈ 140 brokers → ~150–200 with headroom,
typically split into separate clusters (critical domain events vs bulk analytics)
Retention: domain events 7 days: 91 MB/s × 604,800 s ≈ 55 TB × 3 ≈ 165 TB
analytics 3 days: 1.45 GB/s × 259,200 s ≈ 376 TB × 3 ≈ 1.1 PB
Partitions: domain topics ≈ 275 MB/s ÷ ~10 MB/s per consumer partition ≈ 28 minimum;
choose e.g. 128–256 so hundreds of fan-out workers can consume in parallel.
What it means: the "important" event stream is modest (~100 MB/s); analytics is ~15× bigger. Separating them prevents a flood of impression events from delaying fan-out or notifications. Partition count is driven by consumer parallelism, not just throughput.
4.10 Number of application servers
Peak API load ≈ 1.1M requests/s
Assume one app server handles ≈ 1,000 req/s (I/O-bound handlers calling caches/DBs;
could be 200/s in Python, 5,000/s in Go/Java)
Raw servers = 1.1M / 1,000 ≈ 1,100
Target 70% CPU utilisation = 1,100 / 0.7 ≈ 1,570
Survive loss of 1 of 3 zones = × 3/2 ≈ 2,360 → plan ~2,400 servers
DM WebSocket gateways: assume 50M concurrent connections at peak
÷ ~100K connections per server ≈ 500 servers (+ headroom)
The per-server number is the softest assumption — say so, and show how the answer scales with it: if a server only handles 250 req/s, you need ~4× as many (~9,500). That sensitivity is itself a design insight — efficient runtimes and fewer downstream calls per request save thousands of machines.
4.11 Number of database shards
Shard count is driven by whichever constraint is tightest: storage, write throughput, or read throughput. Compute all three and take the max.
| Store | By storage | By write throughput | Result |
|---|---|---|---|
| User DB (PostgreSQL) | 2B users × ~2 KB + other relational tables ≈ 10 TB; ÷ ~1 TB per shard ≈ 10 | User writes are rare (profile edits, sign-ups ~ hundreds/s) → 1 shard would do | ~10 → plan 16 primaries (room to grow), each with 2 replicas = 48 servers; map thousands of logical shards onto them so you can rebalance later |
| Posts + likes + comments (Cassandra) | ~183 TB/yr × 5 yr ≈ 0.9 PB × RF 3 ≈ 2.7 PB ÷ ~2 TB per node ≈ 1,370 nodes | Peak ≈ 195K writes/s × RF 3 ≈ 585K replica writes/s ÷ ~20K per node ≈ 30 nodes | Storage-bound: ~1,400 nodes (throughput would need only ~30) |
| Messages store | 146 TB/yr × 5 × 3 ≈ 2.2 PB ÷ 2 TB ≈ 1,100 nodes | ~70K msgs/s peak × 3 ÷ 20K ≈ 11 nodes | Storage-bound; retention policy is the lever |
What it means: for Instagram-like data, storage usually drives the node count of the write-heavy stores, while RAM drives the cache tier and QPS drives the app tier. Knowing which constraint binds tells you which optimisation matters (compression and TTLs for storage-bound stores; more replicas for read-bound ones). Instagram's publicly described approach of many logical shards mapped onto fewer physical PostgreSQL servers is exactly the "plan for growth" trick in the first row — see Sharding.
4.12 Summary table
| Quantity | Estimate | Design consequence |
|---|---|---|
| DAU / MAU | 500M / 2B | 64-bit IDs; sharded user DB |
| Post writes | ~1.2K/s avg, ~3.5K/s peak | Upload service is not the bottleneck |
| Timeline inserts (fan-out) | ~231K/s avg (~58K/s if only active followers) | Async fan-out workers on Kafka; hybrid push/pull |
| Feed reads | ~116K/s avg, ~350K/s peak | Pre-computed timelines in Redis |
| Total API | ~360K/s avg, ~1.1M/s peak | ~2,400 stateless app servers behind LBs |
| Likes | ~58K/s avg, ~174K/s peak | Write-optimised store, async counters |
| New media | ~580 TB/day; ~212 PB/yr logical; ~1–1.6 EB logical in 5 yrs | Object storage, erasure coding, cold tiering |
| New metadata | ~0.9 TB/day; ~330 TB/yr logical | Sharded Cassandra (~1,400 nodes for 5 yrs) |
| Ingress | ~610 TB/day ≈ 56 Gbps avg | Direct-to-S3 pre-signed uploads |
| Media egress | ~85 PB/day ≈ 7.9 Tbps avg, ~24 Tbps peak | Global CDN mandatory |
| Origin egress (95% CHR) | ~4.25 PB/day ≈ 0.4 Tbps | Origin shield; maximise hit ratio |
| Cache memory | ~9 TB → ~360 nodes with replicas | Redis cluster, capped timelines |
| Kafka | ~1.5 GB/s produce avg; ~150–200 brokers | Separate clusters for domain vs analytics events |
| User DB | ~10 TB → 16 primaries × 3 | Logical shards for future rebalancing |
5. Sanity-check techniques
Estimates go wrong by factors of 1,000 through a single slipped unit. Before you rely on a number, check it with at least one of these:
- Per-user check. Divide the total by the number of users. 85 PB/day ÷ 500M DAU = 170 MB per user per day — about 30 short videos plus 100 photos. Plausible for a heavy media app on mobile. If you'd got 170 GB per user per day, something is off by 1,000×.
- Per-machine check. Does any single box need to do something impossible? "One database handling 350K reads/s" or "one server pushing 8 Tbps" → wrong design or wrong number.
- Two methods. Compute top-down (DAU × actions) and bottom-up (requests per screen × screens per session × sessions). If they disagree by more than ~3×, find out why.
- Ratios. Does the read:write ratio match the product's nature? Does egress:ingress (~140:1) fit "each post viewed hundreds of times"?
- Known anchors. Compare with physical limits you know: a 100 Gbps NIC, a ~2 TB comfortable DB node, ~100K ops/s per Redis node, 86,400 seconds per day.
- Units on every line. Bits vs bytes (×8), per day vs per second (×86,400), KB vs MB (×1,000). Write the unit next to every number.
- Order-of-magnitude rounding. If rounding an input up or down by 2× changes your design decision, the decision is sensitive — say so and pick the safe side.
6. Cheat sheet
TIME RATES SIZE
1 day ≈ 86,400 s ≈ 10^5 s 1M/day ≈ 12/s char 1 B · int 4 B · long/ID 8 B
1 month ≈ 2.5 × 10^6 s 1B/day ≈ 12K/s UUID 16 B · row 100 B–1 KB
1 year ≈ 3 × 10^7 s peak ≈ 2–3 × average photo ~200 KB–2 MB · 1 min video ~10–30 MB
BANDWIDTH STORAGE CAPACITY (rough, per machine)
1 Gbps = 125 MB/s 2^10 ≈ 10^3 (KB), 2^20 (MB) app server: ~200–5,000 req/s
1 TB/day ≈ 12 MB/s ≈ 93 Mbps 2^30 (GB), 2^40 (TB) Redis node: ~100K ops/s, ~50 GB usable
1 PB/day ≈ 12 GB/s ≈ 93 Gbps 2^50 (PB), 2^60 (EB) SQL primary: ~5–20K writes/s, ~1–2 TB
2^31 ≈ 2.1B (int32 limit!) Cassandra: ~10–50K writes/s, ~2 TB
LATENCY Kafka broker: ~100 MB/s
RAM 100 ns · SSD 0.1 ms · same-DC RTT 0.5 ms WebSocket gw: ~100K connections
HDD seek 10 ms · cross-continent RTT 150 ms
FORMULAS
QPS = daily count ÷ 86,400 storage = count/day × size × replicas × days
bandwidth = QPS × payload size servers = peak QPS ÷ (per-server QPS × utilisation)
cache = distinct hot objects × size in-flight = QPS × latency (Little's law)
7. How Instagram uses estimation
Each box in the Instagram diagram can be justified by a number from section 4:
| Box in the diagram | The number that justifies it |
|---|---|
| CDN | ~85 PB/day (~8 Tbps) of media egress — no origin could serve it |
| Object Storage (S3) | ~580 TB/day of new media; ~212 PB/year |
| Feed Cache (Redis) | ~350K feed reads/s peak with a p99 < 300 ms target; working set ~9 TB fits in RAM |
| Feed Fan-out Workers + Kafka | ~20B timeline inserts/day — too many to do synchronously inside a ~1K/s upload request |
| Sharded Cassandra | ~0.9 PB of post/like/comment data over 5 years; ~195K writes/s peak |
| Sharded PostgreSQL + replicas | 2B user rows (exceeds int32 IDs, ~10 TB); reads are far more frequent than writes |
| Stateless app services + load balancer | ~1.1M API requests/s at peak → thousands of servers |
| Separate analytics pipeline | ~250B client events/day (~1.45 GB/s) — 15× the domain event volume |
8. Trade-offs & common pitfalls
✅ Why estimation is worth it
- Turns "it needs to scale" into specific, defensible decisions
- Catches impossible designs early (one DB at 350K QPS)
- Reveals which constraint binds: storage, RAM, CPU or network
- Identifies the biggest cost drivers (video storage, egress)
- Quick: 3–5 minutes with mental arithmetic
⚠️ Limits
- Garbage in, garbage out — assumptions dominate the result
- Averages hide skew (celebrities, viral posts, hot shards)
- Per-server capacity numbers vary 10× by language and workload
- Easy to burn interview time on precision nobody needs
- Real capacity planning needs load tests and production metrics
Common mistakes
- Bits vs bytes. 1 Gbps is 125 MB/s, not 1 GB/s — an 8× error.
- Forgetting peak. Sizing for the average means falling over every evening.
- Forgetting replication and renditions. Raw storage is 1.5–3× logical; each photo exists in 4–8 sizes/formats; videos in a whole bitrate ladder.
- Forgetting write amplification. 1 post = ~200 timeline writes, plus index updates, plus replicas.
- Mixing up DAU and MAU, or using MAU to size daily traffic.
- Over-precision. "1,157.407 QPS" wastes time and signals the wrong priorities. Say "~1.2K/s".
- Computing numbers that drive nothing. Every estimate should end with "…therefore we need X".
- The naive 80/20 cache formula applied to request volume rather than distinct objects (overestimates by orders of magnitude).
- Ignoring the skew. The average user has 200 followers; the top account has hundreds of millions. Hot keys, not averages, break systems.
- Not saying "assume". Present inputs as assumptions, not as facts about a real company.
9. Real-world technologies
| Tool | What it helps estimate or verify | When to use it |
|---|---|---|
| Spreadsheet / notebook (Excel, Google Sheets, Jupyter) | Capacity models with adjustable assumptions | Real capacity planning; sensitivity analysis |
| Cloud pricing calculators (AWS, GCP, Azure) | Converting storage/egress/compute estimates into cost | Budgeting; build-vs-buy decisions |
| Load-testing tools (k6, Locust, Gatling, wrk) | Measured per-server QPS and latency (replacing the "1,000 req/s" assumption) | Before launch; after major changes |
| Benchmarks (redis-benchmark, cassandra-stress, pgbench, Kafka perf tools) | Per-node capacity of data stores | Choosing node sizes and shard counts |
| Monitoring (Prometheus, Grafana, Datadog, CloudWatch) | Real peak factors, growth rates, hit ratios, utilisation | Continuous capacity planning in production |
| Queueing / simulation models | Latency vs utilisation curves, tail behaviour | When headroom decisions are expensive |
10. Interview corner
Estimate the peak QPS of Instagram's home feed.
Assume 500M DAU, each loading ~20 feed pages a day (opening the app several times and scrolling). That's 10B pages/day. Divide by ~86,400 s: ~116K/s average. Traffic is uneven through the day, so peak ≈ 3× → ~350K/s. Implication: we can't compute feeds from the database per request; timelines must be pre-computed and kept in memory, with each page hydrated from caches.
How much storage does Instagram need for new media per year?
Assume 100M posts/day: 85M photos at ~1.5 MB including renditions (~128 TB/day) and 15M videos at ~30 MB including the bitrate ladder (~450 TB/day) → ~580 TB/day, ~212 PB/year logical. With erasure coding (~1.5×) that's ~320 PB raw per year, or ~640 PB with 3× replication. Conclusions: object storage, not databases; video dominates (~78% of bytes); cold-tiering old media is the biggest cost lever.
How would you size the Redis cluster for feed timelines?
Store, per active user, the latest ~500 post IDs with a score: 500 × 16 B = 8 KB, ~16 KB with data-structure overhead. For 500M DAU that's ~8 TB. Add hot post metadata (~200 GB by 80/20 on distinct posts), profiles (~500 GB) and counters (~50 GB): ~9 TB total. At ~50 GB usable per node → ~180 primaries, ~360 nodes with replicas. Check throughput too: ~8M ops/s peak ÷ ~100K ops/s per node ≈ 80 nodes — so memory, not throughput, is the binding constraint.
Why is it misleading to say Instagram has a read:write ratio of 100:1?
Because it depends on what you count. At the API level, likes and DMs are frequent writes, so reads:writes is only ~3:1 under our assumptions. At the content level, each post is viewed ~1,000 times (100B impressions vs 100M posts per day), and media bytes out vs in is ~140:1. The content ratio justifies caching, pre-computed feeds and CDNs; the API ratio warns that the like path needs a write-optimised design.
How many app servers do you need, and what's the weakest assumption?
Peak ~1.1M API requests/s. If one server handles ~1,000 req/s, that's 1,100 servers; at a 70% utilisation target ~1,570; to survive losing one of three zones, ×1.5 → ~2,400. The per-server throughput is the weakest assumption — it varies from ~200 req/s (an interpreted language with many downstream calls) to several thousand. I'd replace it with a load-test number as soon as possible, and note that halving per-request work halves the fleet.
How do you estimate Kafka capacity for Instagram?
Domain events ≈ total writes ≈ 91K/s × ~1 KB ≈ 91 MB/s average. Client analytics events dominate: ~250B/day ≈ 2.9M/s × 500 B ≈ 1.45 GB/s. With RF 3 and peak 3×, brokers write ~14 GB/s; at ~100 MB/s per broker that's ~140 brokers, ~150–200 with headroom, preferably in separate clusters so analytics floods don't delay fan-out. Partition counts follow consumer parallelism (e.g. 128–256 for post events). Retention × throughput × RF gives disk: ~165 TB for 7 days of domain events.
How do you decide the number of Cassandra nodes for posts, likes and comments?
Compute both constraints. Storage: ~183 TB/year logical × 5 years × RF 3 ≈ 2.7 PB; at ~2 TB per node ≈ 1,400 nodes. Throughput: ~195K writes/s peak × RF 3 ≈ 585K replica writes/s; at ~20K per node ≈ 30 nodes. Storage binds, so ~1,400 nodes; the levers are compression, shorter retention for derived data (like rows could be compacted into counts for old posts), and tiering.
11. Check your understanding
Numeric: 300M events per day. Average events per second?
300M ÷ 86,400 ≈ 3,500/s (shortcut: 1M/day ≈ 12/s → 300 × 12 ≈ 3,600/s). Peak ≈ 7–10K/s.
Numeric: a service sends 2 PB per day. What's that in Gbps?
1 PB/day ≈ 11.6 GB/s ≈ 93 Gbps, so 2 PB/day ≈ 23 GB/s ≈ ~185 Gbps average.
Why can't Instagram's user ID be a signed 32-bit integer?
231 − 1 ≈ 2.1 billion — barely above ~2B users and far below the number of posts, likes or messages. IDs must be 64-bit (max ≈ 9.2 × 1018).
Numeric: Your CDN hit ratio improves from 95% to 99%. By how much does origin egress fall?
Misses fall from 5% to 1% of requests — a 5× reduction (from ~4.25 PB/day to ~0.85 PB/day for 85 PB/day of egress).
Scenario: a candidate says "cache = 20% of daily read traffic = 40 TB". What's wrong?
The 80/20 rule applies to distinct objects, not request volume. 10B feed responses mostly reference the same popular posts; caching each response separately would duplicate them. Size by distinct hot items (timelines per DAU, hot posts, profiles) → ~9 TB here.
Numeric: 100M posts/day, average 200 followers each, push fan-out. Timeline inserts per second?
100M × 200 = 20B/day ÷ 86,400 ≈ 231K inserts/s average (~700K/s peak). That's ~200× the post rate — the write amplification of fan-out on write.
Using the "human-scale" latency analogy, why is a feed request that makes 20 sequential DB calls slow?
Each same-DC round trip is ~0.5 ms (plus query time ~1–5 ms) — an eternity relative to memory access. 20 sequential calls ≈ 20–100 ms just waiting, before any tail effects. Batch or parallelise the calls and read from in-memory caches.
You compute 170 GB of media egress per user per day. What should you do?
Sanity-check: that's hours of 4K video per user per day — implausible for an average user. Look for a unit slip (KB vs MB, or per-day vs per-second). The intended estimate here is ~170 MB per user per day.
- Estimation is about orders of magnitude — round aggressively, state assumptions, label units.
- Anchors: 105 s/day, 1B/day ≈ 12K/s, 1 PB/day ≈ 93 Gbps, 210 ≈ 103, RAM ≪ SSD ≪ network ≪ cross-continent.
- Method: assumptions → rates → sizes → resources → sanity check; always include peak, replication, renditions and write amplification.
- Instagram: ~1.2K posts/s but ~350K feed reads/s peak; ~580 TB/day new media; ~8 Tbps egress → CDN; ~9 TB cache; ~1.5 GB/s Kafka.
- Compute every constraint (storage, throughput, RAM) — the tightest one sets the machine count.
- Always finish with "…therefore the design needs X".
Related lessons
- Requirements — where the scale assumptions come from
- Core Principles — Little's law, utilisation, percentiles and availability maths
- CDN — how the 85 PB/day of egress is actually served
- Object Storage — replication vs erasure coding, storage tiers
- Caching — eviction, hit ratios and cache cluster design
- Sharding — turning a shard count into a partitioning scheme
- Message Queues & Kafka — partitions, consumer groups and retention
- News Feed — fan-out write amplification in practice