Skip to lesson
‹

Courses / System Design Interview / Chapter 2

Module 1 · Foundations · Chapter 2 of 39

Back-of-the-Envelope Estimates

17 sections · ~32 min✓ Fact-checked

Builds on What System Design Is: From One Server to Millions. Next up: Abstractions That Hide the Network.

Part 1 · Why Estimate

Numbers decide the design

8:10 pm on the night of a cricket final. On a food delivery app, the checkout button spins and then fails for nearly two of every three orders. The dashboards are puzzling: the checkout servers’ CPUs sit at 25%. The team had sized checkout for an ordinary Friday dinner, with room to spare. Tonight orders arrive twice as fast, and the payment gateway, swamped by every other app, takes 3 seconds a call instead of 1. All 200 checkout threads are waiting on it. Nothing is broken. Two numbers multiplied together a week earlier would have shown that 200 threads could never cover tonight.

An estimate turns vague words like "lots of users" into numbers you can design against: requests per second, storage, bandwidth, servers and money. Engineers make them before a launch, before a sale or a final, in design reviews, and when a cloud bill jumps. You need the right order of magnitude (the nearest power of ten), not an exact answer, because designs change at each factor of ten. As a rough guide:

What the estimate saysWhat the design probably needs
Up to about 1,000 requests a second, under 1 TBTwo app servers behind a load balancer, one relational database with a standby, backups
Reads in the thousands to tens of thousands a secondMore app servers, a cache for hot reads, perhaps read replicas; writes still go to one primary
Writes past roughly 10,000 a second, or tens of TB in one databasePartition (shard) the data, or use a store built to spread writes
Photos, video or other large files, or users on several continentsA blob store and a CDN for the files; more regions for latency or regional outages

Each band starts from a different number: reads bring a cache, writes bring sharding, file sizes bring a blob store. The rest of the chapter sizes the food app for its final night, one number at a time.

Rounding and stating assumptions

Estimates happen in design reviews, chat threads and capacity plans, usually without a spreadsheet, so make the arithmetic easy. Round every input to one or two significant figures and work in powers of ten: 86,400 becomes 10⁵, and 2.6 million becomes 2.5 × 10⁶.

Then write each assumption down before you use it: "20 million daily users, 30 requests each." A reviewer can correct one input without redoing your work, and when real traffic arrives you can see which assumption was wrong. Five habits keep the arithmetic honest:

  • Write the formula first, then put numbers in, keeping the unit on every value.
  • Keep reads and writes separate. They often differ by 10× or 100× and are handled by different parts.
  • Round in whichever direction keeps the maths easy, and note which way you rounded.
  • Sanity-check the result against something you know: does 20 PB sound like a startup or a giant?
  • Work out only the numbers that change a decision; replace the rest with a stated assumption.
An estimate, in order
  1. 1Usersdaily active users, and how many are online at the peak
  2. 2Actionswhat each user does per day, reads and writes counted separately
  3. 3Requests per secondthe average first, then the peak
  4. 4Storageitems per day × size × days kept × copies
  5. 5Bandwidthrequests per second × size, converted to bits for network links
  6. 6Servers, memory and poolspeak load ÷ what one machine handles; threads and connections in flight
  7. 7Moneyone line: which part of the bill dominates

Where real numbers exist, use them: last month’s peak requests per second, bytes per request from the logs, a load test of one server. The formulas stay the same; only the inputs get better.

Part 2 · Numbers to Carry

Units and sizes

Every storage and bandwidth estimate starts from units and the size of one item. Computers count bytes in powers of two, but powers of ten are easier to multiply, and 2¹⁰ = 1,024 is within 3% of 10³, so each unit is roughly a thousand times the last.

Strictly, 1,024 bytes is a kibibyte (KiB). The gap grows to about 13% at a petabyte, less than the usual error in an estimate. Indian numbers need one more conversion: 1 lakh = 10⁵, 10 lakh = 10⁶, 1 crore = 10⁷ and 100 crore = 10⁹. Convert before multiplying; switching systems halfway is a classic slip.

These item sizes are worth knowing by heart. The food app’s own items sit in the middle of the table; when unsure, round up and say so.

ThingRough size
One character of English text (ASCII)1 byte
One character of Hindi or Tamil text (UTF-8)3 bytes
An integer id or a timestamp8 bytes
A UUID16 bytes, or 36 characters as text
A rider’s location ping, with ids and timeabout 100 bytes
An order with its items and status historyabout 2 KB
A dish photo sized for a phone screenabout 100 KB
A photo straight from a phone cameraabout 3 MB
One minute of HD video at 5 Mbpsabout 40 MB

Two habits make the table useful. Count the metadata (ids, timestamps, indexed fields): in a 100-byte ping, the position itself is only 16 bytes. And check media against a bitrate: 5 Mbps is 5 ÷ 8 ≈ 0.6 MB a second, so a minute is about 40 MB.

Time: the 10⁵ trick

With sizes in hand, the next conversion is time. A day has 86,400 seconds. Round it to 10⁵ and any per-day count becomes a per-second rate by dropping five zeros. The answer comes out about 14% low, well inside estimation error.

Per dayPer second, exactPer second, rounded
1 million11.6≈ 12
10 million116≈ 120
100 million1,157≈ 1,200
1 billion11,574≈ 12,000

The first row is the one to memorise: a million a day is about a dozen a second. Every other row is the same fact with zeros added. For the food app, 2 million orders a day is about 23 a second, and 600 million requests a day about 7,000. Working backwards is just as quick: 500 requests a second is roughly 40 to 50 million a day.

Traffic is not spread evenly

People sleep and eat at the same times, so most traffic lands in about 16 waking hours and much of it in a few busy minutes. Dividing by the whole day gives the average; the next part turns it into the peak you design for.

The latency ladder

Rates say how much work arrives; the latency ladder says how long each piece takes, which depends on where the data lives. You need the ladder in your head, not exact figures. To make the gaps feel real, the last column stretches time so that 1 nanosecond becomes 1 second.

OperationRough timeIf 1 ns were 1 second
Read from the CPU’s L1 cacheabout 1 ns1 second
Read from main memory (RAM)about 100 nsunder 2 minutes
Random read from an SSDabout 100 µsabout a day
Round trip inside one data centreabout 0.5 msabout 6 days
Seek on a spinning hard diskabout 10 msabout 4 months
Round trip, Mumbai to Delhiroughly 30 msabout a year
Round trip, Mumbai to the US east coastabout 200 msabout 6 years

The lessons fall out of the ladder. Memory is about 1,000× faster than an SSD, which is why caches exist: the food app’s menu cache answers in under a millisecond from the same data centre, while a database query that misses it costs tens of milliseconds. One cross-continent round trip costs as much as 400 inside a data centre, so keep chatty calls inside one region and put data near users.

Real hardware varies. A fast NVMe drive beats 100 µs, and a busy network is far slower than 0.5 ms. Quote these figures as orders of magnitude, which is all an estimate needs.

Light is slow at this scale

Light in optical fibre travels about 200 km per millisecond. Every 1,000 km between a user and a server adds at least 10 ms to each round trip, before any server does any work.

Part 3 · Traffic, Storage and Bandwidth

Requests per second, average and peak

With units and time settled, the most common estimate is QPS (queries per second, used loosely for requests per second). Build it from users and their actions rather than guessing the final number:

text
average QPS = daily active users × requests per user per day ÷ 86,400
peak QPS    = average QPS × peak factor

Split reads from writes: the food app’s users browse dozens of menu pages for every order they place, and the two sides are handled by different parts. Then multiply by a peak factor, the ratio of the busiest minutes to the daily average. These are assumptions to state, not laws:

Traffic patternPeak factor to assume
An ordinary consumer app across a day2 to 3
Food delivery around lunch and dinner3 to 5
A cricket final or a festival sale5 to 10
Exam results or train bookings at opening time10 to 100, for a few minutes

Choose the factor from the product’s own peaks, and measure it once you have history, per minute rather than per hour: an hourly average hides a first-minute spike that can be several times higher. For the food app, 600 million requests a day averages about 7,000 a second, an ordinary Friday dinner peaks near 4× that, and a final night doubles the Friday rush. The average describes almost no real minute, so design for the peak, not the daily average.

Sizing the final night

Now put the pieces together for the night that broke checkout. A week ahead, while there is still time to add machines, the team asks one question: how many app servers does the final need?

Predict before you watch: on the final night, does the food app need nearer 8, 80 or 800 app servers?
  • Nearer 80: about 6,000 requests a second on average, 8× that at the peak, and about 600 a second per server kept 60% busy.
Animated sceneApp servers for the final night0:16

App servers for the final: ≈ 80 (an ordinary Friday needs about 40: add the rest a week ahead)

Read it as steps

Watch for the peak factor row: one stated assumption turns 10 servers of average traffic into 80.

Sized for the average, the app would get 10 servers; the final needs 80, and an ordinary Friday about 40. With the exact 86,400 the peak is about 56,000 a second, and 80 servers would run near 70% busy instead of 60%: still inside the target, which is why the rounding is safe here.

The same inputs size the writes, and they hold a surprise:

Write streamWorkingAt the final-night peak
Orders placed2 M a day ÷ 86,400 × 8≈ 185 /s
Order writes (items, payment, status changes)185 /s × about 10 rows each≈ 1,900 /s
Rider location pings300,000 riders online ÷ one ping per 5 s60,000 /s

The biggest write stream is not orders but rider pings, about 30 times the order writes. Each stream will end up in a different place, and the capacity page later decides where.

Storage and how long to keep it

Requests come and go; storage stays. Every write adds to it, and it rarely shrinks:

text
storage = new items per day × size per item × days kept × copies

Copies is the factor people forget: many stores keep three copies of every piece of data, and backups add more. A database adds two further factors: indexes, often 30 to 50% on top of the rows, and headroom, because disks should stay under about 70% full. Multiplying by 1.5 and dividing by 0.7 roughly doubles the disk.

Of the four factors in the formula, days kept (the retention) is the one the team chooses. The food app’s product team asks to keep every rider ping for five years, "in case we need it".

Animated sceneKeeping rider pings: five years or 30 days0:16

Kept for 30 days instead: ≈ 16 TB (520 GB × 30: a few machines, not a petabyte)

Read it as steps

Watch for the days kept row: it is the one factor in the storage formula the team chooses, and it moves the answer 60×.

Kept five years, pings need nearly a petabyte, more than ten times everything else the app stores. Kept 30 days, they fit on a few machines. Set retention per kind of data: raw pings for 30 days, a short summary of each trip’s route for years, orders for as long as accounting needs them.

Growth compounds on top. If pings grow 50% a year, the fifth year alone adds more than the first three combined, so state a growth rate or plan to re-estimate every quarter.

Bandwidth

Storage counts bytes kept; bandwidth counts bytes moving each second, and it is one more multiplication:

text
bandwidth = requests per second × bytes per request
          = bytes per day ÷ 86,400

Traffic coming in (ingress) is mostly writes and usually small: the food app’s 60,000 pings a second at 100 bytes are 6 MB a second, about 48 Mbps. Traffic going out (egress) is mostly reads, and media makes it large. Dish photos show how:

StepWorkingResult
Photo bytes per day20 M users × 40 dish photos × 100 KB80 TB
Average rate80 TB ÷ 86,400 s≈ 0.9 GB/s
In bits0.9 GB/s × 8≈ 7.4 Gbps
At the final-night peak7.4 Gbps × 8≈ 60 Gbps

Links are sold in bits per second, so multiply bytes by 8; mixing the two puts you off by 8×. Sixty gigabits a second would keep three to six network cards running flat out at the origin, which is why photos go through a CDN, a network of servers near users that keeps copies of files. If the CDN answers 95% of requests, the origin serves only about 3 Gbps at the peak.

The balance flips for products that mostly upload, such as phone backups or video uploads: there ingress is the big number, so estimate both directions. Cloud providers bill egress per GB, so this number also lands on the bill, which the money page prices.

Part 4 · Machines, Pools and Money

Servers and memory

Once the peak is known, servers are a division. The hard part is the per-server figure, which depends on how much work each request does, so pick a plausible number and state it: for example, one app server handles about 1,000 requests a second of light JSON work with a cache lookup.

text
servers = peak QPS ÷ requests per server ÷ target utilisation
        = 48,000 ÷ 1,000 ÷ 0.6
        = 80 servers

The target utilisation (60% here) is the busiest you let a machine get at the peak, and it buys two things. Room for failure: if 10 of the 80 servers die, the rest run at 69%. And short queues: in a simple queueing model, a request’s time in a server is its service time ÷ (1 − utilisation), 2.5× at 60% but 20× at 95%. A fleet sized at 95% to save money tips over when one machine fails.

Cache memory is a size estimate. The food app’s 300,000 restaurant menus, without photos, average about 20 KB each: 6 GB, which fits in one cache node’s memory, so cache all of it, with a replica for failover. When a dataset is too big, a small share of items usually gets most reads, often summed up as 80/20: cache the hottest 20% and most reads still hit.

What one machine can handle

Every sizing ends in the same division: the load you estimated ÷ what one component can take. These figures are rough, for modern hardware and simple operations; heavy queries or large payloads can cut them by 10×.

ComponentRough capacityWhat it decides
App server1,000 to 10,000 simple requests/sHow many servers sit behind the load balancer
Relational primaryThousands to tens of thousands of simple writes/s; a few to tens of TBWhether you must shard
Cache nodeAbout 100,000+ simple operations/sHow many cache nodes; usually few
Log partitionAbout 10 MB/s, tens of MB/s at bestHow many partitions a stream needs
Connection serverAbout 100,000 mostly idle WebSockets, more with tuningHow many servers hold live connections
DiskNVMe SSD 100,000+ IOPS; network block volume thousandsLocal or network disks for a busy database
Network card10 to 25 GbpsHow many servers a bandwidth figure needs

IOPS means input/output operations per second; a log partition is one ordered slice of a replicated log, covered in Message Queues. Here is the table deciding where the food app’s data lives:

text
orders    1,900 writes/s at the peak → inside one primary’s thousands
          2 M × 2 KB × 365 ≈ 1.5 TB a year, ≈ 3 TB on disk per copy
pings     60,000 writes/s; matching needs only the latest position
          → an in-memory store keyed by rider id, 2 or 3 nodes
menus     all 6 GB in one cache node, plus a replica
photos    60 Gbps at the peak → a CDN, not the app servers

Notice what did not happen: no sharding. A standby replica covers the primary’s failure, and moving orders older than a year to cheaper storage keeps each copy near 3 TB, so a restore at 500 MB a second takes under two hours instead of most of a day. The plan holds until order writes near 10,000 a second.

Threads and connections: Little’s law

Requests per second is a rate, but many limits are counts: threads, database connections, open sockets. Little’s law links the two: the number in flight equals the arrival rate times the time each one spends inside. It explains the night checkout broke.

Animated sceneThe night the checkout pool ran dry0:22

Watch for the thread badge: each checkout holds a thread until the gateway replies

Read it as steps

Little’s law at work: the same arrival rate needs three times the threads when each call takes three times as long.

On an ordinary Friday, 92 orders a second × 1 s kept 92 threads busy, under half the pool. On the final, 185 a second × 3 s needed 555. A slow dependency shows up first as a full pool, long before any CPU looks busy, and a timeout caps the time inside, so it also caps the pool you can ever need.

The same law counts connections. Customers keep a live tracking screen open for about 40 minutes per order, so at 185 orders a second about 185 × 2,400 ≈ 450,000 screens are open: five connection servers at 100,000 sockets each, eight with headroom.

A database pool is different

A bigger gateway pool works because the gateway can take more calls at once. A relational database handles a few hundred connections well, not thousands: when its pool fills, fix the slow query and fail waiting requests fast, or a bigger pool only moves the queue into the database.

The fifth estimate: money

Requests, storage, bandwidth and servers are four estimates. The fifth is money, and often one line is enough: which part of the bill dominates. Run it before any launch that changes what users download. Use rough list prices and check current ones: they change, and large customers pay less.

The food app’s product team wants a 10-second video of each dish that plays by itself as users scroll a menu. Here is the cost check, assuming 20 autoplays per user a day at 1 Mbps and egress at the low end of the range:

LineWorkingPer month
Storing dish photos10 M dishes × 1.1 MB (original plus two sizes) ≈ 11 TB, × $0.02 per GB≈ $220
Serving dish photos today80 TB a day × 30 = 2.4 PB, × $0.05 per GB≈ $120,000
Serving autoplay videos20 M × 20 × 1.25 MB = 500 TB a day, × 30, × $0.05 per GB≈ $750,000

Two things stand out. Serving costs far more than storing: the photos cost about 500× more to deliver than to keep. And autoplay would multiply the delivery bill about seven times before it earns a rupee. The design follows the bill: tap-to-play or Wi-Fi-only videos at a lower bitrate, and a CDN rate negotiated before the launch, not after.

Part 5 · Using Estimates

Checking an estimate

Before an estimate goes into a design doc or a capacity plan, check it for the usual errors. Most are not arithmetic slips but missing factors, and each one costs a predictable multiple:

MistakeHow far offFix
Designing for the daily average2 to 100× too low at the peakMultiply by a stated peak factor
Mixing bits and bytes8×Bytes for storage, bits for network links
Forgetting replicationAbout 3×Multiply storage by the number of copies
Forgetting indexes and headroomAbout 2× too little diskMultiply by 1.5 and divide by 0.7
Keeping everything foreverOften 10× or moreSet retention per kind of data
Dropping units1,000× or moreWrite the unit next to every number
Pricing storage but not egressSeveral times too low for mediaPrice what you serve as well as what you keep
False precisionTime lost, nothing gainedOne or two significant figures

Three checks catch most of the rest. Test the extremes: if your answer means each user uploads 1 GB a day, an input is wrong. Compare with production once it exists: last month’s real peak beats any assumed factor. And use the result: an estimate that changes no decision was not worth making.

"It depends" is not an estimate

Everything depends on something. Pick a number, give the reason, and invite a correction. A stated assumption is a decision that others can check; "it depends" only delays one.

In the interview

In a 45-minute design round, estimates get about three of the 40 design minutes, so work out only the numbers that change a decision and say each assumption before you use it.

Say
"A day is about 10⁵ seconds, so 600 million requests a day is about 6,000 a second; at an 8× peak that is 48,000, about 80 servers kept 60% busy."
Say
"About 1,900 writes a second fits one relational primary, and a year of orders is about 3 TB on disk, so no sharding yet; a standby covers failover."
Say
"Serving photos costs about 500× more than storing them, so the CDN and its rate matter more than the storage tier."
Avoid
Multiplying 86,400 by 365 to four digits on the board. One significant figure leads to the same design and saves minutes.
Avoid
Sizing from the daily average. 6,000 requests a second looks like 10 servers; the 8× peak needs 80.

Wrap-up

TermMeaning
QPSRequests (queries) per second; count reads and writes separately
Peak factorHow many times the average the busiest minutes reach
Order of magnitudeThe nearest power of ten; designs change at each one
RetentionHow long data is kept before it is deleted or archived
Target utilisationHow busy a machine may get at the peak, about 60–70%
Little’s lawIn flight = arrival rate × time each request spends inside
EgressData leaving your servers for users, usually billed per GB
HeadroomSpare capacity kept for spikes, failures and growth

Next: Abstractions That Hide the Network looks at what happens when the calls you just counted cross a network that can be slow, lose messages or run a request twice, like the gateway calls that piled up on the final night.

Part 6 · Check yourself

Quick check

Q1For the final, a teammate proposes 51 servers at 95% busy instead of 80 at 60%, to save money. Why is that a bad plan?

Think it through, then check.

Q2A release adds a 100 ms fraud-check call inside each order’s transaction. At 1,900 writes a second, the 50-connection pool runs dry while database CPU sits at 30%. Why?

Think it through, then check.

Q3For the final, the team wants rider pings every second instead of every 5. What happens to the write rate and the 30-day store?

Think it through, then check.

Q4Product wants every order kept in the orders database forever. Shard by customer now, or move orders older than a year to an archive store?

Think it through, then check.

Q5From What System Design Is: From One Server to Millions: a food app runs on one server. It expects 300 requests a second next month and 3,000 a year later. What do you add, and why?

Think it through, then check.

Next chapter · 3 of 39Abstractions That Hide the Network~32 min · 1 animated scene