# Back-of-the-envelope estimation

> Estimate requests per second, storage, bandwidth, memory and machine counts in minutes, and use the results to make design decisions.

System Design roadmap · Foundations · 18 min read · https://levelcode.org/roadmaps/system-design/estimation

Before you can say "one database is enough" or "this needs sharding", you need numbers. Not precise ones — numbers within a factor of two or three, which you can get in five minutes with round figures and multiplication. This lesson gives you the reference values worth memorising, a method for each kind of estimate, and a full worked example that ends in real design decisions.

## Why rough numbers are enough

Design decisions change at order-of-magnitude boundaries. Whether you need one server or two rarely changes the architecture. Whether you need one server or two hundred changes everything. So the goal is the right power of ten, quickly, with your assumptions written down so others can challenge them.

Three habits make estimates trustworthy:

- **Round aggressively.** A day has 86,400 seconds; call it 100,000 (10⁵). You'll be 15% high, which is noise next to the uncertainty in your user count.
- **Write every assumption on its own line.** "500 million daily users, 20% post once a day" can be argued with. A bare final number can't.
- **Sanity-check against something real.** If your estimate says a chat app needs more servers than Google, re-check the units.

## Numbers worth memorising

**Time and rate conversions:**

| | Value | Rounded |
|---|---|---|
| Seconds in a day | 86,400 | ~10⁵ |
| Seconds in a month | 2.6 million | ~2.5 × 10⁶ |
| 1 million requests/day | 11.6/s | ~12/s |
| 1 billion requests/day | 11,600/s | ~12,000/s |

**Latency, to the nearest order of magnitude** (see [latency numbers](https://levelcode.org/concepts/latency-numbers) for more):

| Operation | Time |
|---|---|
| Read from main memory | ~100 ns |
| Read 1 MB sequentially from memory | ~10–50 µs |
| Random read from an NVMe SSD | ~20–100 µs |
| Round trip inside one data centre | ~0.1–0.5 ms |
| Read 1 MB sequentially from an NVMe SSD | ~0.2–1 ms |
| Round trip across a continent | ~40–80 ms |
| Round trip across the Atlantic or Pacific | ~80–150 ms |

**Rough single-machine capacities** (modern server, simple workload — treat as starting points, then measure):

| Component | Ballpark |
|---|---|
| Stateless API server (Go, simple JSON) | 5,000–20,000 requests/s |
| PostgreSQL, indexed primary-key reads | 10,000–50,000 queries/s |
| PostgreSQL, single-row writes | 2,000–10,000/s, limited by fsync and indexes |
| Redis, simple GET/SET | ~100,000 operations/s per core |
| Network interface | 10–25 Gbit/s ≈ 1–3 GB/s |

These numbers move with hardware, payload size and query shape by 10× in either direction, which is exactly why you write them down as assumptions.

## Traffic: from users to requests per second

Start from users and actions, then convert to per-second rates.

```text
daily active users (DAU)      × actions per user per day   = actions per day
actions per day / 10^5        = average per second
average × peak factor (2–10×) = peak per second
```

The **peak factor** matters more than people expect. Traffic follows the sun, spikes on events, and bursts when a mobile push notification lands on millions of phones at once. Size for the peak, not the average.

Split reads from writes, because they scale differently. Reads can be served from caches and replicas; writes must reach the system of record. A 100:1 read-to-write ratio and a 1:1 ratio lead to very different designs.

## Storage, bandwidth and memory

**Storage** is records per day × size per record × retention, plus overheads:

```text
new records per day × bytes per record × days retained
  × replication factor (often 3)
  × index and format overhead (1.2–2×)
```

**Bandwidth** is requests per second × bytes per response. 2,000 image requests per second at 200 KB each is 400 MB/s, or 3.2 Gbit/s: one network card can carry it, but your cloud egress bill will notice. Data leaving a cloud provider typically costs a few cents per gigabyte, so bandwidth estimates are cost estimates too.

**Memory for a cache** usually follows the 80/20 rule: a small fraction of items gets most of the reads. Caching the hottest 20% of a day's reads is a common starting point:

```text
cache size ≈ distinct items read per day × 0.2 × bytes per item
```

## Concurrency and machine counts

Requests per second alone doesn't tell you how many machines you need. Concurrency does, and [Little's law](https://levelcode.org/concepts/littles-law) connects the two:

```text
concurrent requests in flight = arrival rate × time each request takes
```

At 10,000 requests per second with 50 ms average latency, 500 requests are in flight at any moment. If each instance comfortably handles 100 concurrent requests, you need 5 instances, then add headroom: **run at 50–70% of capacity** so a traffic spike or the loss of one instance doesn't tip you over. The same law sizes database connection pools: 2,000 queries per second at 5 ms each keeps 10 connections busy, so a pool of 20–30 is plenty and a pool of 500 is waste.

> [!WARNING]
> Averages hide the requests users complain about. A service with a 50 ms mean can have a 2-second p99, and if one page fans out to 20 backend calls, most page loads hit at least one slow call. See [tail latency](https://levelcode.org/concepts/tail-latency).

## Worked example: a photo-sharing service

**Assumptions**, each on its own line:

- 50 million daily active users.
- 10% upload one photo a day → 5 million uploads/day.
- Each user views 30 photos a day → 1.5 billion views/day.
- Average photo, after compression, with a few resized versions: 2 MB total.
- Keep photos forever. Peak factor 3×.

**Traffic.**

```text
uploads: 5 × 10^6 / 10^5      ≈ 50/s average, ~150/s peak
views:   1.5 × 10^9 / 10^5    ≈ 15,000/s average, ~45,000/s peak
read:write ratio              ≈ 300:1
```

**Storage.**

```text
per day:  5 × 10^6 × 2 MB     = 10 TB/day
per year: 10 TB × 365         ≈ 3.65 PB/year (before replication)
```

**Bandwidth for views.** Most views load a 200 KB thumbnail-sized version:

```text
45,000/s × 200 KB             = 9 GB/s ≈ 72 Gbit/s at peak
```

**What the numbers decide:**

1. **The images can't be served from your own servers.** 72 Gbit/s of egress is a CDN's job. Your servers will see mostly cache misses.
2. **The images can't live in a database.** 3.65 PB a year belongs in object storage; the database stores metadata (owner, keys, captions), which is tiny by comparison: 5 million rows a day × 500 bytes ≈ 2.5 GB a day.
3. **The metadata database is read-heavy.** At 300:1, read replicas and a cache will absorb the reads; 150 writes per second is easy for a single primary.
4. **Uploads should go straight to object storage** with presigned URLs, so 150 uploads per second of 2 MB each — 300 MB/s — never passes through your API servers.

Four architecture decisions, each traceable to a line of arithmetic. That is what estimation is for.

## Common mistakes

- **Mixing up bits and bytes.** Network speeds are in bits (Gbit/s); storage and file sizes are in bytes. Divide by 8.
- **Forgetting replication and indexes.** Three replicas triples raw storage; indexes often add 20–100%.
- **Sizing for the average.** Real traffic peaks at 2–10× the daily mean.
- **False precision.** "We need 47.3 servers" signals that you trusted inputs that were guesses. Say "around 50, assuming…".

## Practice

Estimate a URL shortener with these assumptions: 100 million new short links a month, a 100:1 redirect-to-create ratio, each link record about 500 bytes, links kept for 10 years, and a peak factor of 5×.

Work out: (1) creates and redirects per second, average and peak; (2) total storage after 10 years, before and after 3× replication; (3) the cache size needed to hold the hottest 20% of a day's redirected links; (4) one design decision each number supports.

**Solution**

**1. Traffic.** 100 million creates a month / 2.5 × 10⁶ seconds ≈ **40 creates/s** average, **200/s** peak. Redirects are 100× that: **4,000/s** average, **20,000/s** peak.

**2. Storage.** 100 million × 12 months × 10 years = 12 billion links. 12 × 10⁹ × 500 B = **6 TB**. With 3× replication, **18 TB**. Large but ordinary: it fits a handful of database nodes, or one large one with room to spare for a few years.

**3. Cache.** A day has about 4,000 × 10⁵ = 400 million redirects. If they touch, say, 100 million distinct links, caching 20% means 20 million entries × 500 B = **10 GB**, which fits in the memory of a single Redis node (with a replica for availability).

**4. Decisions.** 200 creates per second at peak means writes don't need sharding at first. 20,000 redirects per second at peak is too many to send to one database comfortably, but a 10 GB cache that catches most of them makes the database's share small. 6 TB growing to 18 TB with replicas means planning a partitioning scheme by link key before year three, not on day one.

## Key takeaways

- Aim for the right order of magnitude, quickly, with every assumption written down.
- Convert users to requests per second (÷ 10⁵ per day), split reads from writes, and multiply by a peak factor.
- Storage = records × size × retention × replication × overhead; bandwidth = requests per second × response size.
- Little's law turns throughput and latency into concurrency, which sizes fleets and connection pools. Plan to run at 50–70% of capacity.
- Every estimate should end in a decision: CDN or not, database or object storage, one node or many.

## Quiz

1. A service gets 500 million requests a day. Roughly how many per second on average?

   A. About 50
   B. About 500
   C. About 5,000
   D. About 50,000

   **Answer: C.** 500 × 10⁶ / 10⁵ seconds = 5,000 per second. The exact value (5,787) is within rounding of the estimate, which is all a design decision needs.

2. An API handles 4,000 requests per second with an average latency of 25 ms. How many requests are in flight at once?

   A. 16
   B. 100
   C. 160
   D. 4,000

   **Answer: B.** Little's law: L = λW = 4,000/s × 0.025 s = 100 concurrent requests. That number, not requests per second, is what you compare with each instance's concurrency limit.

3. A video service streams at 5 Mbit/s to 200,000 concurrent viewers. What is the egress bandwidth?

   A. 125 Gbit/s
   B. 1 Tbit/s
   C. 1 Gbit/s
   D. 200 Gbit/s

   **Answer: B.** 5 Mbit/s × 200,000 = 1,000,000 Mbit/s = 1 Tbit/s, or 125 gigabytes per second. 125 Gbit/s is the result of confusing bits with bytes. At this volume a CDN is mandatory.

4. Why should you plan to run servers at 50–70% of capacity rather than 100%?

   A. Servers run faster when they're partly idle
   B. Cloud providers charge less for idle capacity
   C. Headroom absorbs traffic spikes and the loss of an instance without overload, and latency rises sharply as utilisation approaches 100%
   D. It keeps CPU temperatures within warranty limits

   **Answer: C.** Queueing delay grows steeply as utilisation nears 100%, and losing one instance of four moves the remaining three from 75% to 100%. Headroom is what keeps both cases survivable.
