Filter concepts by levelShowing all levels.

System Design · Section 5

Back-of-the-Envelope Math

Level
intermediate
Read
18 min
Concepts
4

The fast, rounded estimation seven quantities cover — network bandwidth, storage, memory, cache size, queue depth, CPU needs and database IOPS — built on the unit conversions every one of them silently depends on (bits vs bytes, the 1,024-based ladder), refined by a peak-to-average multiplier and compounding growth over time, and always stated with the one assumption that actually decides how much the answer can be trusted.

This section

What is true here

  1. Seven quantities: bandwidth, storage, memory, cache size, queue depth, CPU needs, database IOPS.
  2. 1 byte = 8 bits — network links are rated in bits, storage and payloads in bytes; each KB/MB/GB/TB step is ×1,024.
  3. Peak-to-average is a same-day multiplier; growth compounds month over month like interest.
  4. An estimate is only as solid as its least-certain input — name the dominant assumption, state a range.

What you will be able to do

  • Name all seven back-of-the-envelope quantities for a given system
  • Convert correctly between bits and bytes, and across the KB/MB/GB/TB ladder
  • Apply a peak factor and a compounding growth rate to the same base estimate
  • Identify which input to an estimate has the widest plausible range and state the estimate as a range around it

The quantities and units

What to estimate on the spot, and the conversions every one of those numbers depends on.

What a back-of-the-envelope estimate covers

standardintermediate

A back-of-the-envelope pass covers seven quantities: network bandwidth, storage, memory, cache size, queue depth, CPU needs and database IOPS — done fast, on the spot, with rounded numbers rather than a spreadsheet.

Think of it as

Section 4's five categories are what a capacity plan documents; this is the wider, faster set a design conversation reaches for on the spot — two more quantities (CPU needs, database IOPS) that only come up once the conversation gets into how a single node actually does the work, not just how much traffic arrives.

text
Seven quantities, on the spot, rounded:
  bandwidth · storage · memory · cache size
  queue depth · CPU needs · database IOPS

What we're doing: Walk through all seven quantities for one system in a single pass, the way a design conversation actually moves through them.

what-to-estimate.txttext
System: a URL shortener redirect endpoint,
3,000 peak RPS, 200-byte average response.

  Bandwidth:  3,000 × 200 B × 8 bits ≈ 4.8 Mbps
  Storage:    20M short URLs × 300 B ≈ 6 GB
  Memory:     hot 5% of URLs get 80% of traffic ≈ 300 MB
  Cache size: sized to that same 300 MB working set
  Queue depth: none — redirects are synchronous, no queue involved
  CPU needs:  3,000 × 1ms CPU/request = 3 cores at 100% util
  DB IOPS:    mostly cache hits, ~600 reads/sec reach disk
4
Bandwidth converts to bits, not bytes, because network links are rated in bits per second.
8
Some systems genuinely have no queue — naming that explicitly is as useful as a number would be.
10
CPU needs comes from per-request work times RPS, the same shape as the bandwidth calculation but for compute instead of network.

Why this works: A design conversation moves through these seven quantities quickly, one after another, to find which one is the actual bottleneck — bandwidth and CPU rarely constrain the same system equally, and naming all seven is what surfaces which one does.

Stopping at request rate and skipping CPU and IOPS

Wrong

text
"3,000 peak RPS, so bandwidth is about 4.8 Mbps
and storage is 6 GB." (CPU and database IOPS
never estimated)

Better

text
"3,000 peak RPS: 4.8 Mbps bandwidth, 6 GB
storage, 3 CPU cores at 100% util, and about
600 IOPS reaching the database."

What you see: Bandwidth and storage look comfortably provisioned, but the service is CPU-bound in production because the per-request compute cost was never estimated alongside the network and storage numbers.

Why: Bandwidth and storage are the two most commonly estimated quantities, which is exactly why CPU and database IOPS are the two most commonly skipped — and either one can be the actual bottleneck a design never noticed.

The seven quantities, grouped by the resource each one bounds

Over the wire

Network bandwidth

RPS x average payload, converted to bits — links are rated in bits per second

On disk

Storage

records x size x retention

Database IOPS

reads/sec plus writes/sec that actually reach the disk, after the cache

In RAM

Memory

the working set, not the total data size

Cache size

hot subset x item size

Work per second

CPU needs

work per request x RPS, read as cores at 100% utilisation

Queue depth

arrival rate against service rate

  • Seven quantities, rounded, on the spot
  • Over the wire
    • Network bandwidth — RPS x average payload, converted to bits — links are rated in bits per second
  • On disk
    • Storage — records x size x retention
    • Database IOPS — reads/sec plus writes/sec that actually reach the disk, after the cache
  • In RAM
    • Memory — the working set, not the total data size
    • Cache size — hot subset x item size
  • Work per second
    • CPU needs — work per request x RPS, read as cores at 100% utilisation
    • Queue depth — arrival rate against service rate

The seven back-of-the-envelope quantities

The seven back-of-the-envelope quantities
QuantityAnswersRough method
Network bandwidthwill the link saturate?RPS × avg payload size, in bits
Storagehow much disk, and for how long?records × size × retention
Memorywhat fits in RAM?working-set size, not total data size
Cache sizehow big a cache actually helps?hot subset × item size
Queue depthis the queue keeping up?arrival rate vs service rate
CPU needshow many cores at 100% util?work per request × RPS
Database IOPSwill the disk be the bottleneck?reads/sec + writes/sec to disk

Together

text
A search endpoint, all seven quantities:

  Bandwidth:  2,000 RPS × 4 KB response ≈ 64 Mbps
  Storage:    50M documents × 2 KB ≈ 100 GB
  Memory:     working set is the top 10% of docs ≈ 10 GB
  Cache size: same 10 GB, sized to fit in one node's RAM
  Queue depth: indexing jobs arrive faster than they drain -> backlog
  CPU needs:  2,000 RPS × 5ms CPU/request = 10 cores at 100% util
  DB IOPS:    2,000 reads/sec, mostly cache misses ≈ 400 IOPS to disk

Remember: Seven quantities for a fast estimate: bandwidth, storage, memory, cache size, queue depth, CPU needs, database IOPS.

See also: estimation categories · unit conversions

The unit conversions every estimate depends on

corebeginner

Every capacity number rests on two conversions: the 1,024-based ladder from bytes to KB/MB/GB/TB, and bits vs bytes — network links are rated in bits per second, but storage and payload sizes are almost always given in bytes.

Think of it as

A byte is 8 bits — that single fact is the most common estimation error, because storage is measured in bytes but network capacity is measured in bits. Converting a 100 Mbps link into bytes means dividing by 8, not multiplying. Above bytes, each unit is 1,024 of the one below it, not 1,000 — close enough for a rough estimate, but the gap compounds at TB scale.

text
bytes = bits / 8
KB = bytes / 1,024
MB = KB / 1,024
GB = MB / 1,024
seconds/day   = 86,400
seconds/month ≈ 2,592,000  // 30-day approximation

What we're doing: Convert a network link rating (bits) into a payload throughput figure (bytes), the conversion every bandwidth estimate needs.

unit-conversions.txttext
A service needs to serve 500 GB of video per day
over a 1 Gbps network link. Does the link have
enough headroom?

  500 GB/day -> bytes/sec:
    500 GB × 1024 × 1024 × 1024 / 86,400 ≈ 6.2 MB/sec

  1 Gbps link -> bytes/sec:
    1,000,000,000 bits/sec / 8 ≈ 125 MB/sec

  6.2 MB/sec needed vs 125 MB/sec available:
  comfortably under capacity.
6
Storage is given in GB (bytes); dividing the daily total by 86,400 seconds gives a bytes-per-second rate.
9
The link rating is in bits, so it has to be divided by 8 before it can be compared to a bytes-per-second demand figure.
11
Only after both sides are in the same unit (bytes/sec) can the comparison actually mean something.

Why this works: Comparing a bits-per-second link rating directly against a bytes-per-second demand figure — without converting one to match the other — produces a number that is off by a factor of 8, which is large enough to flip "comfortably provisioned" into "will saturate."

Comparing a bandwidth demand in bytes against a link rated in bits

Wrong

text
"We need 6.2 MB/sec and the link is rated at
1 Gbps, so we need 6.2 out of 1,000 — plenty
of headroom." (1 Gbps treated as 1,000 MB/sec)

Better

text
"1 Gbps = 125 MB/sec after dividing by 8.
We need 6.2 MB/sec, so we're using about 5%
of the link's real byte capacity."

What you see: A link that looked like it had 1,000x headroom actually has 20x headroom — still fine here, but the same mistake on a tighter margin turns a real capacity risk into a false "plenty of room" conclusion.

Why: Treating a bits-per-second rating as if it were bytes-per-second overstates available capacity by 8x — small on a link with huge headroom, but large enough to hide a genuine bottleneck on a tighter one.

A 100 Mbps link, converted to bytes/sec

100 Mbps

100,000,000 bits/sec

÷ 8

bits -> bytes

12.5 MB/sec

12,500,000 bytes/sec

  1. 100 Mbps — 100,000,000 bits/sec
  2. ÷ 8 — bits -> bytes
  3. 12.5 MB/sec — 12,500,000 bytes/sec

The conversion ladder

The conversion ladder
FromToFactor
BytesBits× 8
KBBytes× 1,024
MBKB× 1,024
GBMB× 1,024
TBGB× 1,024
DaySeconds× 86,400
Month (30d)Seconds× 2,592,000

Together

text
A 100 Mbps network link, in bytes per second:

  100 Mbps = 100,000,000 bits/sec
  ÷ 8 (bits -> bytes)
  = 12,500,000 bytes/sec
  = 12.5 MB/sec

Remember: 1 byte = 8 bits (network links are bits, storage is bytes); 1 KB/MB/GB/TB step is ×1,024; 1 day = 86,400 seconds.

See also: what to estimate · core formulas

Advertisement

Reasoning about the result

Adjusting for peak load and growth, and knowing how much to trust the number that comes out.

Peak-to-average ratios and growth over time

standardintermediate

A single estimate answers "what does the system need today, at peak" — but a design also has to survive the same system six or twelve months from now, which means applying a growth rate on top, not just a peak factor.

Think of it as

Peak-to-average is a multiplier applied once, to today's traffic, to size for the worst moment of a normal day. Growth is different: it compounds over time, the way interest does — a system growing 10% a month is not 120% of today's size in a year, it is roughly 3.1x, because each month's growth applies to an already-larger base.

text
peak_rps      = average_rps * peak_factor
size(months)  = today_size * (1 + monthly_growth_rate) ** months

What we're doing: Apply a peak factor to size for today, and a compounding growth rate to check the same design against a year from now.

peak-and-growth.txttext
Average RPS today: 1,157. Peak factor: 3x.
Traffic growing 8%/month.

  Peak RPS today       = 1,157 × 3          ≈ 3,471
  Average RPS, 12 mo    = 1,157 × 1.08^12   ≈ 2,915
  Peak RPS, 12 mo       = 2,915 × 3         ≈ 8,745

A design sized only for today's 3,471 peak RPS
falls short by 12 months — 2.5x short.
4
The peak factor is applied first, to size for the worst moment of today.
5
Growth compounds on the average, not the peak — the peak factor is re-applied afterward to the grown average.
8
A system sized only for today's peak has no margin left for the traffic it will actually see well before a year passes.

Why this works: A design that only accounts for today's peak is already out of date the day it ships, because real traffic keeps growing. Compounding the growth rate before re-applying the peak factor is what shows how much margin a design actually needs to hold for longer than a few months.

Adding growth flatly instead of compounding it

Wrong

text
"8% a month for 12 months is 96% more traffic,
so plan for about 2x today's numbers."

Better

text
"8% a month compounds to about 1.08^12 ≈ 2.5x
over 12 months — plan for 2.5x, not 2x."

What you see: A design provisioned for "2x current load in a year" runs out of headroom around month 10, because the real compounded growth was closer to 2.5x, not the flat 2x the estimate assumed.

Why: Growth rates compound the same way interest does — multiplying month over month, not adding up flatly — and the gap between a flat estimate and the real compounded number grows larger the further out the estimate reaches.

Compounding against adding flatly — 100 GB at 10% a month

Both lines are computed from the two formulas, not measured. They are indistinguishable for the first quarter, which is what makes the flat guess feel safe; by month 12 they are 94 GB apart (314 against 220) and the gap widens every month after.

  • 0: Compounded — 100 x 1.10^N 100, Flat guess — 100 + 10N 100
  • 3: Compounded — 100 x 1.10^N 133, Flat guess — 100 + 10N 130
  • 6: Compounded — 100 x 1.10^N 177, Flat guess — 100 + 10N 160
  • 9: Compounded — 100 x 1.10^N 236, Flat guess — 100 + 10N 190
  • 12: Compounded — 100 x 1.10^N 314, Flat guess — 100 + 10N 220

Compounding growth at 10%/month, starting from 100 GB

Compounding growth at 10%/month, starting from 100 GB
MonthFormulaSize
0 (today)100 × 1.10^0100 GB
3100 × 1.10^3≈ 133 GB
6100 × 1.10^6≈ 177 GB
12100 × 1.10^12≈ 314 GB

Together

text
A dataset at 100 GB today, growing 10%/month:

  size(months) = 100 GB × (1.10 ^ months)

  6 months:  100 × 1.10^6  ≈ 177 GB
  12 months: 100 × 1.10^12 ≈ 314 GB

A flat "10% × 12 = 120% more" guess would say
220 GB — the real, compounded answer is 314 GB.

Remember: Peak RPS = average × peak factor, applied once; growth compounds — size after N months = today × (1 + rate)^N, not a flat sum.

See also: what to estimate · core formulas

Knowing which assumptions dominate the result

coreintermediate

Every estimate rests on a handful of guessed inputs, but they rarely matter equally — one or two dominate the final number, and those are the ones worth stress-testing, not every input treated as equally uncertain.

Think of it as

An estimate multiplies several factors together, and the factor with the widest plausible range — not necessarily the biggest number — is the one that swings the result the most. Naming that dominant assumption up front turns "this estimate might be wrong" into "this estimate is wrong if X is wrong," which is the actually useful, checkable version of the same caveat.

text
for each input:
  ask: how wide is the plausible range?
  the widest range = the dominant assumption
  re-run the estimate at its low and high ends

What we're doing: Identify which of three inputs to a storage estimate dominates the result, and show the estimate's real range once that assumption is stress-tested.

estimate-confidence.txttext
Storage estimate for a new logging feature:

  Log volume: 50M events/day (measured, ±5%)
  Avg event size: 500 bytes (measured, ±10%)
  Retention period: "probably 90 days" (guessed, 30-365)

  At 90 days: 50M × 500B × 90  ≈ 2.25 TB
  At 30 days: 50M × 500B × 30  ≈ 0.75 TB
  At 365 days: 50M × 500B × 365 ≈ 9.1 TB
3
Log volume and event size are measured, narrow-range inputs — not where the real uncertainty lives.
5
Retention period is a guess with a 12x range (30 to 365 days) — this is the dominant assumption.
8
Re-running the formula across that range shows the estimate genuinely spans 0.75 TB to 9.1 TB, not a comfortable single number.

Why this works: Presenting "2.25 TB" as the estimate hides that the real uncertainty is 12x wide, entirely driven by one guessed input. Naming the dominant assumption turns a false-precision number into an honest range, and tells the team exactly which question to go answer before committing to a storage budget.

Presenting an estimate as a single precise number

Wrong

text
"Storage needed: 2.25 TB." (stated as if it
were as solid as the measured inputs it was
built from)

Better

text
"Storage needed: 0.75-9.1 TB, depending on
retention period — that's the assumption to
confirm before committing to a number."

What you see: A storage budget is approved at 2.25 TB, and the team is surprised months later when the real retention requirement turns out to be a full year, blowing past the number nobody flagged as uncertain.

Why: A single number reads as more certain than it is when it is built from a mix of measured and guessed inputs. The estimate is not wrong to give a central number — it is wrong to give only that number without naming which input could move it by an order of magnitude.

Finding the assumption that dominates a storage estimate

Log volume

50M events/day — measured, ±5%. Narrow range.

Event size

500 bytes — measured, ±10%. Narrow range.

Retention period

"probably 90 days" — guessed, ranges 30-365. This dominates.

Re-run at both ends

30 days ≈ 0.75 TB, 365 days ≈ 9.1 TB — state the range, not 2.25 TB alone.

  1. Log volume — 50M events/day — measured, ±5%. Narrow range.
  2. Event size — 500 bytes — measured, ±10%. Narrow range.
  3. Retention period — "probably 90 days" — guessed, ranges 30-365. This dominates.
  4. Re-run at both ends — 30 days ≈ 0.75 TB, 365 days ≈ 9.1 TB — state the range, not 2.25 TB alone.

Same estimate, three assumptions of very different confidence

Same estimate, three assumptions of very different confidence
AssumptionConfidencePlausible range
Requests/day (from analytics)high — measured100M ± 5%
Average payload size (measured)high — measured4 KB ± 10%
Cache hit ratio (guessed, no cache built yet)low — guessed60%-95%

Together

text
Database load estimate for a new feature:

  Requests/day:      100M (measured, high confidence)
  Avg payload:        4 KB (measured, high confidence)
  Cache hit ratio:    guessed at 80% (no cache built yet)

  DB reads/sec at 80% hit ratio: ~231
  DB reads/sec at 60% hit ratio: ~463
  DB reads/sec at 95% hit ratio: ~58

The cache hit ratio, not the request volume,
decides whether the database needs 58 or 463
reads/sec of headroom.

Remember: An estimate is as solid as its least-certain input — find the assumption with the widest plausible range and state the estimate as a range around it.

See also: peak and growth · what to estimate

Advertisement