The numbers worth memorising
You don't need precision. You need to never be wrong by a factor of a thousand.
| Operation | Time | In "human" scale (1 ns = 1 second) |
|---|---|---|
| L1 cache reference | 1 ns | 1 second |
| Branch mispredict | 3 ns | 3 seconds |
| L2 cache reference | 4 ns | 4 seconds |
| Mutex lock/unlock | 17 ns | 17 seconds |
| Main memory reference | 100 ns | 1.5 minutes |
| Compress 1 KB (snappy) | 2 µs | 33 minutes |
| Read 1 MB sequentially from RAM | 3 µs | 50 minutes |
| NVMe SSD random read | 20 µs | 5.5 hours |
| Round trip within a datacenter | 500 µs | 6 days |
| Read 1 MB sequentially from NVMe | 100 µs | 1.2 days |
| HDD seek | 8 ms | 3 months |
| Zurich → Frankfurt round trip | 8 ms | 3 months |
| Zurich → us-east-1 round trip | 90 ms | 3 years |
If the table is too much, keep the three ratios:
- Memory is ~100× faster than SSD.
- SSD is ~100× faster than a spinning disk seek.
- A cross-continent round trip is ~1,000,000× a memory reference.
Data sizes, similarly rounded: 2^10 ≈ thousand, 2^20 ≈ million, 2^30 ≈ billion. A UUID is 16 bytes, a timestamp 8, a typical JSON API response 1–10 KB, a photo 2 MB, a minute of 1080p video ~50 MB.
The estimation recipe
Five steps, always the same order. Say each number out loud as you go — the interviewer is grading the derivation, not the answer.
- Users → requests. DAU × actions per user per day ÷ 86,400 = average QPS.
- Average → peak. Multiply by 2–3 for daily peak. Higher if there's a scheduled event (a match kickoff, a flash sale, a 09:00 commute spike).
- Requests → resources. Per request: how many bytes over the wire, how many DB reads, how much CPU.
- Storage. Items × size × replication factor × retention. Then add index overhead.
- Bandwidth. QPS × payload size, in both directions. Don't forget egress cost.
Useful constant: 86,400 seconds in a day ≈ 100,000. So 1 M events/day ≈ 12/sec, and 1 B/day ≈ 12,000/sec. That single approximation does most of the work.
Worked example: driver location pings
A ride-hailing service across Switzerland and Austria.
Given: 200,000 drivers online at peak, each pinging location every 4 seconds. A ping is
driver_id, lat, lon, heading, timestamp — call it 64 bytes of payload, 200 bytes on the
wire with headers.
Write throughput
200,000 drivers ÷ 4 s = 50,000 writes/sec at peak
Average, off-peak ≈ 15,000 writes/sec
50k writes/sec is the number that decides the architecture. It rules out "just write each ping to Postgres" — that's a sustained 50k row-inserts/sec, achievable but expensive and wasteful for data that's obsolete in 4 seconds.
Bandwidth
50,000 × 200 bytes = 10 MB/s = 80 Mbit/s inbound
Trivial. Bandwidth is not the constraint here — which is itself worth saying, because it tells the interviewer you checked rather than assumed.
Storage, if we kept everything
50,000/s × 86,400 s = 4.3 B pings/day
4.3 B × 64 bytes = 276 GB/day raw
× 3 replicas = 830 GB/day
× 90 days retention = 75 TB
75 TB to answer "where was this driver last Tuesday". That forces the real design question: do we need the history at all? Usually the answer is: keep current position in memory (200k drivers × 64 bytes = 13 MB, which fits in a single Redis instance with room to spare), and downsample the trail — one point per 30 seconds, kept 30 days, is 1/8th the volume.
Why you cannot run servers at 95%
Here's the number people get wrong most often. A server at 90% utilisation does not have 10% headroom — its latency has already multiplied.
Queueing theory says that with random arrivals, average latency scales as 1/(1-ρ) where ρ
is utilisation. At 50% you wait about as long as you're served. At 90%, ten times. At 99%,
a hundred times. Drag the slider:
Two things to take from it:
The knee is real and it's around 70–80%. Below it, latency is roughly flat and traffic growth is cheap. Above it, small traffic increases produce large latency increases. This is why capacity plans target 60–70% peak utilisation — the remaining 30% isn't waste, it's the buffer that keeps p99 sane.
Pooling beats splitting. Push the server slider up. Sixteen servers behind one balancer at 90% utilisation sit at ~1.4× service time; a single server at 90% sits at 10×. Same utilisation, radically different latency, purely because a shared queue absorbs bursts that would stall an individual queue. This is the mathematical argument for load balancing, for connection pooling, and against pinning work to specific nodes.
And note what the tail does. The p99 stat is roughly ln(100) ≈ 4.6× the queueing
component, so at 80% utilisation on one server your mean is 5× but your p99 is around 19×.
Tail latency degrades far faster than the mean, which is why an alert on average
response time will not fire until users have been suffering for a while.
Sanity numbers for servers
Rough, defensible, and enough to reason with:
| Thing | Order of magnitude |
|---|---|
| A modern app server, simple JSON endpoint | 5k–20k QPS |
| Same, with a couple of DB queries | 500–2k QPS |
| Postgres, simple indexed reads | 10k–50k QPS |
| Postgres, writes | 5k–20k/sec |
| Redis, single instance | 100k+ ops/sec |
| Kafka, single broker | 100 MB/s+ |
| One machine's RAM | 64–512 GB |
| 10 Gbit NIC | 1.25 GB/s |
State your assumption when you use one: "I'll assume 1,000 QPS per app server, so 50k peak needs 50 servers, call it 65 with headroom." An interviewer who disagrees with 1,000 will say so, and now you're having a design conversation instead of guessing silently.
What to take away
- Three buckets: ns for CPU/memory, µs for SSD/local network, ms for disks and distance.
- 86,400 ≈ 100,000. Peak ≈ 2–3× average.
- The five-step recipe: users → QPS → peak → per-request cost → storage and bandwidth.
- An estimate is a design tool. If it doesn't change anything, you asked the wrong question.
- Latency scales as 1/(1-ρ). Plan for 60–70% peak utilisation, and remember tails degrade faster than means.
- Pooling requests across servers beats partitioning them into separate queues.
Check yourself
-
A service handles 1 billion events per day. Roughly what is the average QPS?
There are 86,400 seconds in a day, which rounds to 100,000. So a billion per day is about 10,000 per second, and the more precise figure is ~11,600. Rounding 86,400 to 100,000 is the single most useful approximation in estimation.
-
A single server is running at 90% utilisation. Roughly what has happened to its mean latency compared to an idle server?
Mean response time scales as 1/(1-utilisation), so 90% utilisation gives about a 10x multiple of raw service time. This is why capacity plans target 60-70% at peak: the headroom is what keeps latency flat, not waste.
-
You need to store the current location of 200,000 online drivers, 64 bytes each. Where does that fit?
200,000 x 64 bytes is about 13 MB, which fits in memory many times over. Recognising that the working set is tiny prevents an enormous amount of unnecessary architecture, and only the estimate reveals it.
-
Sixteen servers behind one load balancer at 90% utilisation have much lower latency than one server at 90% utilisation. Why?
Utilisation per server is identical in both cases, so it is not about doing less work. With a pooled queue, a burst arriving at a busy server can be served by an idle one, which is exactly what a single-server queue cannot do. This is the core mathematical argument for load balancing.