Back-of-the-Envelope Estimation for System Design
The arithmetic that turns a vague brief into a concrete architecture. Learn to size QPS, storage and bandwidth in under two minutes - and to know instantly whether a design is plausible.
Covers: QPS maths, storage sizing, bandwidth, latency numbers every engineer should know, powers of two, peak factors
Estimation is what separates a design from a drawing. The number 40,000 writes per second tells you a single Postgres primary will not do. The number 40 writes per second tells you it will do comfortably for years. Same diagram, opposite conclusions - and you cannot reach either without arithmetic.
30-second answer
Take DAU, multiply by actions per user per day to get daily requests, divide by 86,400 seconds to get average QPS, then multiply by a peak factor of 2 to 3. For 100 million DAU doing 20 actions a day: 2 billion requests a day, ÷ 86,400 ≈ 23,000 average QPS, so roughly 50,000–70,000 QPS at peak. Then split that by read/write ratio, because 50,000 reads and 500 writes are completely different engineering problems.
The formula
Traffic is never uniform. Most consumer products see 2–3× the daily mean at peak hour; a few (live sport, ticket drops) see 10×+.
Worked example - a Twitter-like feed
State assumptions
100 M DAU. Each user reads the feed 10 times a day and posts 0.1 times a day. That is a 100:1 read:write ratio - say the ratio out loud, it is the most consequential number you will produce.Reads
100 M × 10 = 1 B feed loads/day ÷ 86,400 ≈ 11,600 QPS average, so ~35,000 QPS peak.Writes
100 M × 0.1 = 10 M posts/day ÷ 86,400 ≈ 116 QPS average, ~350 QPS peak.Draw the conclusion
350 writes/second is comfortable for a single well-tuned primary. 35,000 reads/second is not - that is the number that forces a cache and read replicas. The ratio told you where to spend your complexity budget.
Sanity anchors
| Rough capacity | Order of magnitude |
|---|---|
| A modest application server | 1,000–10,000 QPS of simple work |
| Managed relational primary, simple indexed queries | 5,000–20,000 QPS |
| Relational primary, write throughput | 1,000–10,000 writes/s before tuning hurts |
| Redis, single node | 100,000+ ops/s |
| One modern NVMe SSD | ~100,000+ IOPS, ~1–3 GB/s sequential |
| 1 Gbps NIC | ~125 MB/s |
You will never be marked down for approximating these. You will be marked down for having no idea whether 50,000 QPS on one box is plausible.
Say these points
- QPS = DAU × actions/day ÷ 86,400, then × 2–3 for peak.
- Round 86,400 to 10⁵ for instant mental arithmetic.
- Always split into reads and writes - the ratio decides the architecture.
- Finish with a decision: what does this number rule in or out?
Avoid these mistakes
- Computing average QPS and forgetting the peak multiplier.
- Producing a number and never using it to justify a component.
- Treating reads and writes as one aggregate figure.
- Getting lost in precision - 23,148 QPS is no more useful than 'about 20 thousand'.
Expect these follow-ups
- Your product is a live-sports app. How does the peak factor change?
- How would you estimate QPS for a feature that does not exist yet?
- At 35,000 read QPS with a 90% cache hit rate, how many QPS reach the database - and is that fine?
30-second answer
Storage = objects per day × average size × retention, then multiply by a replication factor (usually 3) and add roughly 30% for indexes, metadata and headroom. Bandwidth = QPS × average payload size, computed separately for ingress and egress - egress is usually far larger for media products and is the line item that actually costs money. Always express the result per day and per year, because the yearly figure is what decides your storage tier.
Storage
Worked example - a photo product with 10 M uploads/day at 2 MB average, kept forever, replicated 3×:
- Raw per day: 10 M × 2 MB = 20 TB/day
- Per year: 20 TB × 365 ≈ 7.3 PB/year
- With 3× replication: ≈ 22 PB/year
- Plus thumbnails (say 3 sizes at ~10% each) and metadata: ≈ 29 PB/year
Bandwidth
Compute ingress and egress separately. For the same photo product: uploads are 10 M/day ≈ 116/s × 2 MB ≈ 232 MB/s ingress. If each photo is viewed 100 times, egress is 100× that - around 23 GB/s - which is precisely why the CDN exists and why 95%+ of that traffic must never reach your origin.
Powers of two, and the sizes worth memorising
| Item | Approximate size |
|---|---|
| ASCII / UTF-8 character | 1 byte |
| UUID (binary / string) | 16 B / 36 B |
| Unix timestamp (int64) | 8 B |
| A tweet-sized text row with metadata | ~300 B |
| A typical JSON API response | 1–10 KB |
| A web page with assets | 1–3 MB |
| A phone photo | 2–5 MB |
| One minute of 1080p video | ~50–100 MB |
| Power of 2 | Value | Name |
|---|---|---|
| 2¹⁰ | ~1 thousand | KB |
| 2²⁰ | ~1 million | MB |
| 2³⁰ | ~1 billion | GB |
| 2⁴⁰ | ~1 trillion | TB |
| 2⁵⁰ | ~1 quadrillion | PB |
Say these points
- Multiply by replication factor and add ~30% overhead - raw size is never the real number.
- Separate ingress from egress; for media, egress dominates and drives cost.
- Express storage per year - that is the figure that picks the storage tier.
- Use scientific notation to keep whiteboard arithmetic error-free.
Avoid these mistakes
- Forgetting replication, then being surprised by the real bill.
- Ignoring thumbnails, derived data, indexes and backups.
- Quoting one bandwidth figure without splitting read from write.
- Storing multi-megabyte blobs in the primary database.
Expect these follow-ups
- How would a 90-day retention policy change the yearly storage figure?
- What is the cheapest way to cut that 23 GB/s of egress?
- How do you estimate storage when the average object size has a long tail?
30-second answer
The ladder spans nine orders of magnitude: L1 cache around 1 ns, main memory around 100 ns, an SSD read around 100 µs, a same-datacentre round trip around 500 µs, a disk seek around 10 ms, and a cross-continent round trip around 150 ms. The practical consequence is that memory is roughly a thousand times faster than SSD and a hundred thousand times faster than a cross-ocean hop - so the design question is never 'is this fast?' but 'how many times do I cross which boundary?'.
Using them: count the boundary crossings
Suppose a page needs 50 pieces of data and your service fetches them one at a time from a database in the same datacentre. 50 × 0.5 ms of network alone is 25 ms before the database does any work. Batch those into one query and you pay 0.5 ms. The win came from removing round trips, not from making anything faster.
| Design choice | Approximate cost | Implication |
|---|---|---|
| Read from local process memory | ~100 ns | Effectively free |
| Read from Redis, same DC | ~0.5–1 ms | Cheap; do it liberally |
| Read from database, indexed, same DC | ~1–5 ms | Fine, but not in a loop |
| Read from database, unindexed scan | 10 ms – seconds | This is your outage |
| Cross-region call (EU ↔ US) | ~80–150 ms | Never in a synchronous request path |
| Cross-continent round trip (US ↔ Asia) | ~150–250 ms | Design around it, do not fight it |
The N+1 pattern, in latency terms
# 1 + N round trips: ~0.5 ms each => ~25 ms of pure network
posts = db.query("SELECT * FROM posts WHERE feed_id = ?", feed_id) # 1
for post in posts: # N = 50
post.author = db.query("SELECT * FROM users WHERE id = ?", post.user_id)
# 2 round trips: ~1 ms total
posts = db.query("SELECT * FROM posts WHERE feed_id = ?", feed_id)
authors = db.query("SELECT * FROM users WHERE id IN ?", {p.user_id for p in posts})
by_id = {a.id: a for a in authors}
for post in posts:
post.author = by_id[post.user_id]Say these points
- Memory ≈ 100 ns, SSD ≈ 100 µs, same-DC RTT ≈ 0.5 ms, cross-continent ≈ 150 ms.
- Optimise by removing round trips, not by shaving microseconds.
- The speed of light sets a hard floor - that is why CDNs and regional replicas exist.
- Parallel fan-out turns rare tail latency into common tail latency.
Avoid these mistakes
- Making a database call inside a loop (the N+1 problem).
- Putting a cross-region call in a synchronous user request path.
- Assuming parallel calls are free because they overlap.
- Quoting exact nanosecond figures - orders of magnitude are what matter.
Expect these follow-ups
- A page makes 100 parallel calls, each with p99 = 100 ms. Estimate the page's p99.
- How do hedged requests help, and what do they cost?
- When is it acceptable to do a synchronous cross-region call?
30-second answer
Divide target QPS by realistic per-server throughput, then divide again by your target utilisation, then add redundancy. If a server handles 2,000 QPS and you run at 50% utilisation for headroom, 50,000 QPS needs 50 servers, plus enough extra to survive losing an availability zone - so around 75 across three zones. The number matters less than the reasoning: state per-server capacity, utilisation target and failure budget explicitly.
1. Per-server capacity
Estimate from work per request. If a request costs ~10 ms of CPU and a server has 8 usable cores, that is 8 ÷ 0.01 = 800 QPS at 100% CPU. For light I/O-bound work assume higher; for heavy CPU work, lower. Say your assumption out loud.2. Target utilisation
Never plan for 100%. Queueing theory is brutal: as utilisation approaches 1, queue length - and therefore latency - goes to infinity. Plan for 50–70%, so a traffic spike does not become an outage.3. Redundancy
You must survive losing a zone. Across three AZs, each carries a third of traffic, so each must be able to carry half when one dies. In practice: size for N, then add ~50%.4. Round up and sanity-check
50,000 ÷ 800 = 63 at full load; ÷ 0.6 utilisation = ~105; × 1.5 for zone loss = ~155. If that feels absurd, revisit step 1 - usually the per-request cost estimate was wrong, not the arithmetic.
Average queue wait for M/M/1. ρ is utilisation, 1/μ is service time. The pole at ρ = 1 is the whole story.
Little's Law - the other formula worth knowing
Concurrency = arrival rate × time in system. Independent of the arrival distribution, which is what makes it so useful.
At 50,000 QPS with 20 ms average latency, concurrent in-flight requests = 50,000 × 0.02 = 1,000. That single number sizes your thread pools, your connection pools and your load balancer's concurrency limits. It is also the fastest way to spot an impossible configuration: if you need 1,000 concurrent requests and your database connection pool is 50, you have found the bottleneck before writing any code.
Say these points
- Servers = QPS ÷ per-server capacity ÷ utilisation target, then × redundancy factor.
- Plan for 50–70% utilisation; latency explodes non-linearly as you approach saturation.
- Little's Law (L = λW) sizes thread pools and connection pools instantly.
- State your per-request cost assumption - that is the number the interviewer will probe.
Avoid these mistakes
- Sizing for 100% utilisation and being surprised by latency spikes.
- Ignoring the requirement to survive an availability-zone failure.
- Forgetting that the database, not the app tier, is usually the real limit.
- Autoscaling on a metric that only moves after users are already suffering.
Expect these follow-ups
- Your autoscaler adds instances at 80% CPU but latency has already tripled. What do you change?
- How does Little's Law help you choose a connection pool size?
- When would you deliberately run at 85% utilisation?
Showing 4 of 4 questions for back-of-the-envelope-estimation.
Check your understanding
4 questions · no sign-up, nothing stored
Hands-on challenge
Build it - this is what you talk about in a deep-dive round.
Size a video-sharing platform end to end
Produce a complete capacity plan for a video platform with 20 million DAU. Show every assumption. The goal is a defensible order of magnitude reached in under ten minutes.
Requirements
- Estimate peak upload QPS and peak view QPS, stating your per-user activity assumptions.
- Compute storage per day and per year for original files plus three transcoded renditions, with 3× replication.
- Compute origin egress with and without a CDN at a 95% offload rate.
- Use Little's Law to size the concurrent request count for the view path.
- State the single number that most constrains the design, and what you would change because of it.
Stretch goals
- Add a 30-day hot / 1-year warm / archive-after tiering policy and recompute the storage cost profile.
- Estimate how many transcoding workers you need if one worker handles 1× real-time and average video length is 8 minutes.