TL;DR

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.

🧠 Analogy Planning a wedding. You don't know exactly how many guests will come, but you estimate: ~200 invited, ~80% attend → ~160 people; each eats ~0.5 kg of food → ~80 kg; 10 per table → 16 tables; a bus holds 50 → 4 buses. Every number is approximate, but it's good enough to book the right venue, order roughly the right food and not hire a single taxi for 160 people. If you'd guessed "maybe 20 guests", you'd have booked the wrong building. Capacity estimation is the same: roughly right beats precisely wrong.

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 2Exact value≈ Power of 10NameWhere you meet it
28256—1 byte holds 256 valuesA byte; small enums
2101,024103 (thousand)1 KB (KiB)A short JSON object; a tweet-sized record
21665,536~6.5 × 104—TCP port range; 16-bit counters overflow
2201,048,576106 (million)1 MB (MiB)A photo
230~1.07 billion109 (billion)1 GB (GiB)A movie; RAM per process
231~2.1 billion2 × 109—Max signed 32-bit int — fewer than Instagram's ~2B users! IDs must be 64-bit
232~4.3 billion4 × 109—IPv4 address space; unsigned 32-bit int
240~1.1 trillion1012 (trillion)1 TB (TiB)A large SSD; a DB shard
250~1.13 × 10151015 (quadrillion)1 PB (PiB)A day of Instagram-scale media egress is tens of PB
260~1.15 × 101810181 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)
💡 Data-size rules of thumb ASCII character = 1 byte (UTF-8: 1–4 bytes); integer/ID = 4 or 8 bytes; timestamp = 8 bytes; UUID = 16 bytes; a typical DB row with a few fields = 100 B–1 KB; a compressed phone photo = 100 KB–2 MB; a minute of 720p video ≈ 10–30 MB depending on bitrate. When unsure, round up — real systems carry indexes, replication and overhead.

2.2 Handy conversions

FactValueShortcut
Seconds per day86,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 second1M/day ≈ 12/s
1 billion per day≈ 11,574 per second1B/day ≈ 12K/s
Bits vs bytes1 byte = 8 bitsNetwork in bits (Gbps), storage in bytes (GB)
1 Gbps125 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 averageDepends on daily curvepeak ≈ 2–3 × average (use 3× for safety; viral events more)
Concurrent usersDepends 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.

OperationClassic latencyIn µs / msLesson for design
L1 cache reference0.5 nsCPU caches are effectively free
Branch mispredict5 ns
L2 cache reference7 ns
Mutex lock/unlock25 nsContention, not the lock itself, is the cost
Main memory reference100 ns0.1 µsRAM is the fast tier → caches (Redis)
Compress 1 KB (Snappy/Zippy)~3 µs3 µsCompression is cheap vs network
Send 1 KB over 1 Gbps network10 µs10 µsBandwidth rarely the bottleneck for small payloads
Read 4 KB randomly from SSD~150 µs (NVMe: ~20–100 µs)0.15 msSSD random reads OK; batch them
Read 1 MB sequentially from memory250 µs (modern: tens of µs)0.25 msSequential is king
Round trip within same data centre500 µs0.5 msEach service hop costs ~0.5–1 ms → limit chatty calls
Read 1 MB sequentially from SSD1 ms (NVMe: ~0.2 ms)1 ms
HDD disk seek10 ms10 msAvoid random I/O on spinning disks; log-structured storage
Read 1 MB sequentially from HDD20 ms20 msCheap bulk storage (cold media tier)
Packet round trip California → Netherlands → California150 ms150 msPhysics: 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):

 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

1. AssumptionsDAU, actions/userobject sizespeak factor 2. Ratesper day → per secread vs writeavg and peak QPS 3. Sizesstorage/day, /year× replicationbandwidth in/out 4. Resourcesservers, shardscache nodesbrokers, CDN 5. Sanity checkper-user, per-boxsecond method→ design impact if a number looks absurd, revisit the assumptions Formula skeleton: QPS = (users × actions per user per day) ÷ 86,400 · storage = items/day × size × replication × days
Estimation is a pipeline: each stage multiplies the previous one by a rate or a size. Sanity checks close the loop.
  1. State assumptions explicitly and round them to friendly numbers (500M not 487M). Write them on the board.
  2. Convert per-day counts into per-second rates, separately for reads and writes. Multiply by a peak factor (2–3×).
  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.
  4. 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).
  5. Sanity-check and, most importantly, say what the number means for the design.
💡 Arithmetic tricks Work in scientific notation and add exponents: 500M × 20 = 5×108 × 2×101 = 10×109 = 1010. Then 1010 / 105 = 105 = 100K/s. Keep one significant digit until the end. Label units on every line (requests/day, bytes/s) — unit mistakes are the most common error.

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

InputAssumption
Users2B MAU, 500M DAU
Posts100M/day: 85M photo posts, 15M video posts (carousels folded into the average size)
Stories200M/day
Feed page loads20 per DAU per day (each page ≈ 10 posts)
Profile views, Stories-tray loads10 each per DAU per day
Likes / comments5B/day / 500M/day (10 likes, 1 comment per DAU)
Follows100M/day; average ~200 followees per user
Search queries1B/day (2 per DAU)
DMs2B messages/day
Media sizesphoto upload 1 MB + renditions 0.5 MB; video upload 15 MB + renditions 15 MB; story ~1.5 MB
Media consumedper DAU per day: ~100 images × 200 KB, ~30 videos × 5 MB (includes Stories and Reels views)
Peak factor3× average

4.2 Requests per second (QPS)

Rule: QPS = per-day count ÷ 86,400. Using "1B/day ≈ 12K/s":

OperationPer dayAverage QPSPeak QPS (3×)Type
Feed page loads500M × 20 = 10B~116K~350KRead
Profile views5B~58K~174KRead
Stories tray loads5B~58K~174KRead
Comment list reads2B~23K~70KRead
Search queries1B~12K~35KRead
Total reads23B~267K~800K
Likes5B~58K~174KWrite
DMs sent2B~23K~70KWrite
Comments500M~5.8K~17KWrite
Stories posted200M~2.3K~7KWrite
Posts100M~1.2K~3.5KWrite
Follows100M~1.2K~3.5KWrite
Total writes~7.9B~91K~275K
All API requests~31B~360K~1.1M

What it means:

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.

New data per year (logical), log scale — each grid line is 10× 1 TB10 TB100 TB1 PB10 PB100 PB1 EB Media (posts) ~212 PB DM messages ~146 TB Likes ~91 TB Comments ~55 TB Post metadata ~37 TB Media outweighs all metadata combined by ~650× — different problems, different storage systems.
On a log scale the difference is stark: metadata is "big data", media is "enormous data".

4.5 Metadata storage

DataRow size (assume)VolumePer dayPer year (logical)
Posts~1 KB (ids, caption ~200 B, media keys, location, timestamps, indexes)100M/day100 GB~37 TB
Likes~50 B (post_id 8 + user_id 8 + timestamp 8 + overhead)5B/day250 GB~91 TB
Comments~300 B500M/day150 GB~55 TB
DMs~200 B (text messages; media goes to object storage)2B/day400 GB~146 TB
Follow graph~30 B per edge, stored in both directions2B 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 ratioOrigin egress per dayOrigin bandwidthReduction vs no CDN
90%8.5 PB~98 GB/s ≈ 790 Gbps10×
95%4.25 PB~49 GB/s ≈ 394 Gbps20×
99%0.85 PB~9.8 GB/s ≈ 79 Gbps100×
500M users85 PB/day of views CDN edgesserve 95% from cache≈ 80.75 PB/day Origin (S3)4.25 PB/day ≈ 7.9 Tbps ≈ 0.4 Tbps (misses) Arrow thickness ≈ traffic. A 95% hit ratio turns an impossible origin load into a manageable one.
CDN offload at a 95% hit ratio.

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 dataCalculationMemory
Feed timelines (post IDs + scores) for DAU500M 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 DAU500M × 1 KB~500 GB
Like/comment counters for hot posts1B posts × ~50 B (key + 2 counters + overhead)~50 GB
Sessions / auth tokens500M × 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.

StoreBy storageBy write throughputResult
User DB (PostgreSQL)2B users × ~2 KB + other relational tables ≈ 10 TB; ÷ ~1 TB per shard ≈ 10User 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 nodesPeak ≈ 195K writes/s × RF 3 ≈ 585K replica writes/s ÷ ~20K per node ≈ 30 nodesStorage-bound: ~1,400 nodes (throughput would need only ~30)
Messages store146 TB/yr × 5 × 3 ≈ 2.2 PB ÷ 2 TB ≈ 1,100 nodes~70K msgs/s peak × 3 ÷ 20K ≈ 11 nodesStorage-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

QuantityEstimateDesign consequence
DAU / MAU500M / 2B64-bit IDs; sharded user DB
Post writes~1.2K/s avg, ~3.5K/s peakUpload 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 peakPre-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 peakWrite-optimised store, async counters
New media~580 TB/day; ~212 PB/yr logical; ~1–1.6 EB logical in 5 yrsObject storage, erasure coding, cold tiering
New metadata~0.9 TB/day; ~330 TB/yr logicalSharded Cassandra (~1,400 nodes for 5 yrs)
Ingress~610 TB/day ≈ 56 Gbps avgDirect-to-S3 pre-signed uploads
Media egress~85 PB/day ≈ 7.9 Tbps avg, ~24 Tbps peakGlobal CDN mandatory
Origin egress (95% CHR)~4.25 PB/day ≈ 0.4 TbpsOrigin shield; maximise hit ratio
Cache memory~9 TB → ~360 nodes with replicasRedis cluster, capped timelines
Kafka~1.5 GB/s produce avg; ~150–200 brokersSeparate clusters for domain vs analytics events
User DB~10 TB → 16 primaries × 3Logical 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:

  1. 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×.
  2. 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.
  3. 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.
  4. Ratios. Does the read:write ratio match the product's nature? Does egress:ingress (~140:1) fit "each post viewed hundreds of times"?
  5. 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.
  6. 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.
  7. 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 diagramThe 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 + replicas2B 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
📸 In Instagram Two public Instagram engineering facts show estimation thinking in action. First, their widely cited sharded-ID scheme uses 64-bit IDs (41 bits of milliseconds since a custom epoch, 13 bits of logical shard ID, 10 bits of per-shard sequence). Do the maths: 213 = 8,192 logical shards; 210 = 1,024 IDs per shard per millisecond → ~1M IDs per second per shard; 241 ms ≈ 69.7 years of timestamps. Those bit widths are a capacity estimate frozen into a format (see ID Generation). Second, the decision to create thousands of logical shards up front and map them onto a small number of physical PostgreSQL servers was explicitly about growth: moving a logical shard to a new machine is easy; re-splitting data later is hard. Both decisions came from asking "how big will this get?" before it got big.

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

9. Real-world technologies

ToolWhat it helps estimate or verifyWhen to use it
Spreadsheet / notebook (Excel, Google Sheets, Jupyter)Capacity models with adjustable assumptionsReal capacity planning; sensitivity analysis
Cloud pricing calculators (AWS, GCP, Azure)Converting storage/egress/compute estimates into costBudgeting; 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 storesChoosing node sizes and shard counts
Monitoring (Prometheus, Grafana, Datadog, CloudWatch)Real peak factors, growth rates, hit ratios, utilisationContinuous capacity planning in production
Queueing / simulation modelsLatency vs utilisation curves, tail behaviourWhen 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.

🎯 Key takeaways

Related lessons