System Design Road

Part 1 · Lesson 1.3

The Argument That Napkin Math Settled

Back-of-the-envelope estimation14 steps · 13 min

Where we are: Chirp has a few hundred users, and the founders have just raised a small amount of money. Before spending it, they have to decide how big a system to build. This lesson uses only the round trips from lesson 1.1 and the numbers from lesson 1.2.

What you’ll learn

  • A repeatable method: users to requests, storage and bandwidth
  • Which numbers change a design and which don't
  • How Chirp found its biggest cost in photo traffic
  • The mistakes that make estimates wrong
Lesson trace

Lesson 1.3 The Argument That Napkin Math Settled

Step 1 of 14 · 1 min · The story

The founders had their first real disagreement in a coffee shop, about three weeks after the "Who to follow" incident.

Arjun had been reading engineering blogs. He wanted to "build it right from the start": Kubernetes, a Cassandra cluster, a message queue, separate services for posts, users, and feeds. "If we take off, we won't have time to rebuild everything," he said. "Every company that scaled says they wish they'd planned for it."

Meera thought this was a way to spend six months building infrastructure for users they didn't have. "One server and Postgres," she said. "We'll fix it when it breaks."

They went back and forth for an hour. Both of them were partly right, and neither could prove it, because they were both arguing from feelings. Then Meera pulled a napkin over and said, "Okay. How many users do we actually think we'll have in a year? Let's just work it out."

Twenty minutes later the argument was over. The napkin showed that Arjun's setup was wildly more than they needed for the database and servers. It also showed something neither of them had thought about at all, which was going to cost them more than every server combined.

This lesson is about doing that napkin math. It's called back-of-the-envelope estimation, and it might be the single most useful habit in system design.

Step 2 of 14 · 1 min

What estimation is for

The point isn't to get the right number. You can't: you don't know how many users you'll have, how often they'll post, or how big their photos will be. The point is to find out which decisions the numbers force, and which ones they don't.

If the answer comes out as "about 10 writes per second," it doesn't matter whether the true number is 5 or 30. Any database handles that. If it comes out as "about 50,000 writes per second," it doesn't matter whether it's 30,000 or 80,000 either. You need a very different design. Estimation tells you which side of a line you're on, and the lines are usually far apart.

That's why it's fine to round aggressively. Being off by 2× rarely changes a design. Being off by 100× does, and estimation catches that.

Step 3 of 14 · 1 min

The few numbers you need

Seconds in a day: 86,400. Round it to 100,000. It makes the arithmetic easy, and the 15% error doesn't matter.

That gives a handy conversion:

Per day Per second (roughly)
1 million 10
10 million 100
100 million 1,000
1 billion 10,000

Traffic isn't flat. People use apps in the evening more than at 4 am, and more on weekends and holidays. A peak of 2–3× the daily average is a reasonable starting point for most apps. For anything tied to events (a sports final, New Year's Eve, a big product launch), it can be 10× or more for short periods. Design for the peak, not the average.

Sizes, in powers of a thousand:

Roughly Example
1 KB a thousand bytes a short post plus its metadata
1 MB a thousand KB a photo from a phone, compressed
1 GB a thousand MB about a million posts
1 TB a thousand GB about a million photos
1 PB a thousand TB where large companies' photo storage lives

Bits and bytes. Network speeds are quoted in bits per second, storage in bytes. There are 8 bits in a byte. "1 Gbps" is 125 MB per second, not 1,000. Mixing these up is the most common estimation mistake there is, and it's an 8× error.

Step 4 of 14 · 1 min

The method

Every estimate follows the same chain. Start from people, end at machines:

  1. Users: how many use the app on a typical day?
  2. Actions: what do they do, and how often?
  3. Requests per second: actions per day ÷ 100,000, then multiply for the peak.
  4. Storage: what does each action save, and for how long?
  5. Bandwidth: how much data moves for each action?
  6. Memory: what needs to be fast, and how big is it?

Write every assumption down. When someone disagrees, you'll be able to see exactly which assumption they disagree with, and change it, instead of arguing about the conclusion.

Step 5 of 14 · 3 min

Chirp's napkin

Meera and Arjun agreed on an optimistic target: 1 million daily active users in a year. Here's the napkin, written out properly.

Assumptions

  • 1M daily active users
  • 10% of them post on a given day, about 2 posts each
  • Everyone opens the feed about 10 times a day
  • 20% of posts include a photo
  • A post (text plus metadata) is about 1 KB in the database, including indexes
  • A photo is about 500 KB after compression, and Chirp stores it in 3 sizes (original, feed size, thumbnail), adding about 50% more
  • The feed shows about 10 photos per screen, each about 100 KB at feed size
  • Peak is 3× average

Requests

Napkin math
Posts:       1M × 10% × 2    = 200,000 per day  → about 2 per second  (peak ~6)
Feed opens:  1M × 10         = 10M per day      → about 100 per second (peak ~300)

Each feed open also triggers a few other API calls (profile, notifications, and so on). Call it 5 calls per open: about 500 requests per second on average, 1,500 at peak.

Is that a lot?

This is where lesson 1.2 comes in. A single modern application server running ordinary code can handle somewhere in the hundreds to low thousands of simple requests per second. A single well-configured Postgres server can handle thousands of simple reads and writes per second, more if most data fits in memory.

6 writes per second is nothing. 1,500 requests per second at peak needs maybe two or three application servers, and you'd want at least two anyway so the app stays up when one fails. The database load is comfortable for one server.

Arjun's Cassandra cluster is designed for hundreds of thousands of writes per second. Chirp, at its optimistic one-year target, needs six.

Storage

Napkin math
Post text:  200K posts/day × 1 KB         = 200 MB per day  → about 75 GB per year
Photos:     200K × 20% = 40K photos/day
            40K × 500 KB × 1.5 (3 sizes)  = 30 GB per day   → about 11 TB per year

Look at how different those are. All the text Chirp will store in a year fits on a laptop. The photos are 150 times bigger.

Don't forget the multipliers that real systems add:

  • Replicas: you'll want at least one copy of the database on another machine (lesson 2.5). ×2.
  • Backups: at least one more copy somewhere else. ×1 more.
  • Growth: you're estimating the first year, but storage keeps everything from every year.

So the database is about 75 GB × 3 ≈ 225 GB after a year. One server, easily. The photos are about 11 TB a year, growing every year, and they clearly don't belong in the database at all. That's exactly decision D2 in the Stage 0 simulation: where to store images. Lesson 2.3 is about the answer, object storage.

Bandwidth: the surprise

This is the line that ended the argument.

Napkin math
Feed opens:  10M per day
Photos seen: 10 per open × 100 KB = 1 MB per open
Total:       10M × 1 MB = 10 TB per day of photos sent to phones

Turn that into a rate:

Napkin math
10 TB/day ÷ 100,000 s ≈ 100 MB/s ≈ 800 Mbps on average
                                   ≈ 2.4 Gbps at peak

Then turn it into money. Cloud providers charge for data leaving their network, often somewhere in the range of $0.05 to $0.09 per GB at this kind of volume (check your provider; prices change and drop with volume):

Napkin math
10 TB/day × 30 days = 300 TB/month = 300,000 GB
300,000 GB × $0.05–0.09 ≈ $15,000–27,000 per month

Neither founder had put photos in their mental picture of "scaling." Arjun was worried about the database. Meera was worried about wasted engineering time. Meanwhile, the thing that would actually threaten Chirp's bank account at a million users was sending pictures to phones.

That changed the plan more than anything else on the napkin. It meant photos needed to be resized carefully (a thumbnail doesn't need to be 100 KB), served with good compression, and delivered through a CDN, which caches files near users and usually costs less per GB than serving them from your own servers (lesson 2.3). It also meant they should track bandwidth cost from day one.

Memory

What needs to be fast? The data behind the most frequent requests: profiles of active users, recent posts, the social graph for active users.

Napkin math
Active user profiles:  1M × 1 KB  = 1 GB
Last 2 days of posts:  400K × 1 KB = 400 MB

That's a couple of gigabytes, which fits in RAM on one ordinary server. A cache will be easy when they need it (lesson 2.4).

Step 6 of 14 · 1 min

From the real world: 50 times the plan

Here's what it looks like when a careful estimate meets a viral launch. Pokémon GO launched in July 2016, running on Google Cloud. Google later described the numbers: the teams had planned for a launch target of 1×, with a worst case of roughly 5× that. Actual traffic reached about 50× the target, ten times the worst case.

The first days had long stretches where players couldn't log in or the game wouldn't respond. Google's reliability engineers worked alongside Niantic, the game's developer, to add capacity ahead of the growth, many tens of thousands of CPU cores for the game's container cluster, and to fix bottlenecks as each new one appeared.

Two lessons for your own napkin:

  • An estimate is a range, and you need a plan for being outside it. Nobody could have predicted 50×. But you can decide in advance what happens at 10× the worst case: which features turn off, whether logins queue instead of failing, which limits you'll raise. Pokémon GO's teams were rebuilding pieces under live load because there wasn't that plan.
  • Your estimate's biggest number is the one you're least sure of. Daily users times actions per user is easy arithmetic on two guesses. Write down which of your inputs is the shakiest, and how the design changes if it's wrong by 10×. Usually only one or two parts of the system care (here: login, and the map data around each player), and those are the parts to design with room to grow.

For Chirp, Meera's rule became: "Estimate it. Then ask what breaks first at ten times that, and what we'd do. If the answer is 'rewrite everything,' we've designed it wrong."

Step 7 of 14 · 1 min

Going deeper: why 90% busy is not "10% spare"

The method says to divide peak load by what one server handles. There's a catch: how busy you let each server get changes how fast it answers, and not in a straight line.

Requests don't arrive evenly. Even at an average of 800 a second, some milliseconds bring a burst, and a burst has to wait in a queue. The busier the server, the more likely a new request finds others ahead of it. For the simplest model of random arrivals (called M/M/1 by queueing theorists), the average time a request spends in the system is:

Napkin math
time in system = work time ÷ (1 − utilization)

At 50% busy, a request spends twice its own work time in the system. At 80%, five times. At 90%, ten times. At 95%, twenty. And p99 is several times worse than those averages. The last few percent of capacity cost as much latency as everything before them.

Switch the diagram to one shared queue and you'll see the second, more hopeful result. Eight servers each with their own queue behave like eight separate M/M/1 queues: a request stuck behind a slow one waits, even if a neighbour is idle. Eight servers pulling from one shared queue (M/M/8) behave far better at the same utilization: at 80% busy, time in system is about 1.2× the work time instead of 5×. This is why a load balancer that sends work to whichever server is free beats a fixed assignment, and why one big connection pool beats many small ones.

What this means for estimates:

  • Plan for 60–70% at peak, not 100%. The "spare" capacity is what keeps latency flat.
  • Pool where you can. Shared queues, shared pools and least-loaded routing get more out of the same machines.
  • When something gets slower, it gets busier, and then slower still. That loop is behind many outages in Part 6.

Step 8 of 14 · 1 min

What the napkin decided

Question Answer from the napkin Decision
Do we need a distributed database? ~6 writes/s at peak in a year No. One Postgres server, plus a replica later
How many app servers? ~1,500 requests/s at peak Two or three, mostly for redundancy
Where do photos go? ~11 TB/year and growing Not the database. Object storage
What will cost the most? ~10 TB/day of photo traffic Bandwidth. Resize photos, use a CDN, watch the bill
Do we need a big cache? A few GB of hot data Not yet, and it'll be easy when we do

Meera was right about the servers and database. Arjun was right that some things need planning up front: they just weren't the things he'd been reading about. Getting photo storage wrong early would be painful to undo, so it was worth doing properly from the start. Kubernetes could wait.

And if Chirp ever did get to 50 million users, they'd redo the napkin, and it would point to different decisions. That's the rest of this course.

Step 9 of 14 · 1 min

Run your own napkin

Here's Chirp's napkin with the assumptions turned into sliders. Push the number of users up and see what breaks first. Then try the photo size and see how much it moves the bill compared with everything else.

Step 10 of 14 · 1 min

Where estimates go wrong

Forgetting the peak. An app that averages 100 requests per second and peaks at 1,000 needs to be designed for 1,000. Events make this worse: the moment a big match ends, everyone opens the app at once.

Forgetting the multipliers. Replicas, backups, indexes, logs, the three sizes of every photo. Storage estimates are often low by 3–5× because of these.

Bits versus bytes. An 8× error, in either direction, from one letter.

Using the average user. Most users are light, and a few are very heavy. For capacity, totals are what matter, so averages are fine. For the worst case on a single machine (the most-followed account, the busiest chat room), you need to think about the heaviest user, not the average one. Lesson 4.4 is entirely about this.

False precision. "We need 3.72 TB" sounds more serious than "about 4 TB," but it isn't more accurate. It just makes it harder to notice that an assumption was a guess.

Forgetting to sanity-check. When you get a number, compare it with something you know. "10 TB a day of photo traffic for a million users" works out to about 10 MB per person per day, which is roughly 100 photos. For someone who scrolls a social feed several times a day, that's believable. If it had come out as 10 GB per person, something would clearly be wrong.

Step 11 of 14 · 1 min

In the simulation

At the start of Stage 0 you'll see Chirp's assumptions: users, posting rate, photo share, and so on. Before you make your first decisions, do the napkin math yourself and write it down. When you reach later stages and things start breaking, go back and check: was it a number you could have estimated? Most of the time, it will be.

Open the simulation →

Step 12 of 14 · 1 min

If you're here for an interview

Most design interviews include a few minutes of estimation, and candidates often get it wrong in one of two ways: they skip it, or they spend ten minutes on arithmetic nobody needed.

What works well:

  • Estimate only what changes the design. Requests per second, storage size, and bandwidth usually matter. Exact memory per server usually doesn't.
  • Round loudly and say so. "That's about 100,000 seconds a day, so 10 million a day is about 100 per second."
  • Say what the number means. "That's about 6 writes per second, which one database handles easily, so I won't shard." The conclusion is the point; the arithmetic is just how you got there.
  • Look for the surprise. In many problems one dimension dominates, like bandwidth for Chirp. Finding it early shows you understand where the real cost is.

Step 13 of 14 · 2 min

Try these yourself

1. A chat app has 5 million daily users. Each sends 40 messages a day. How many messages per second on average, and at a 3× peak?

5M × 40 = 200M per day ÷ 100,000 ≈ 2,000 per second, about 6,000 at peak. That's well within reach of a single well-tuned database for writes, but delivering each message to other people is a separate (and bigger) question. That's the chat scenario in Part 7.

2. Those messages average 200 bytes each, and the app keeps them forever. How much storage per year, including one replica and one backup?

200M × 200 bytes = 40 GB per day → about 15 TB per year. ×3 for the replica and backup ≈ 45 TB per year. Now it's beyond a single ordinary server within a year or two. The text-only chat app needs more storage planning than Chirp's text did, because it writes far more.

3. A server's network card is rated at 10 Gbps. How many 100 KB photos per second can it send at full speed?

10 Gbps = 1.25 GB/s = 1,250 MB/s. 1,250 MB ÷ 0.1 MB = about 12,500 photos per second, in theory. In practice you'd plan for well below full speed. If you got 100,000 instead, you probably forgot to divide bits by 8.

4. Chirp halves the feed photo size from 100 KB to 50 KB by using a newer image format. Using the napkin's numbers, about how much does that save per month?

Photo traffic drops from about 300 TB to 150 TB per month. At $0.05–0.09 per GB, that's roughly $7,500–13,500 per month, from a change to image encoding. Bandwidth-heavy products often get their biggest savings from making files smaller, not from changing servers.

5. Arjun says, "But what if we get 100 million users?" Redo the request estimate. Does the design change?

Everything scales by 100×: about 600 writes per second at peak, about 150,000 requests per second at peak, and about 1 PB of photo traffic per day. Yes, it changes. Many more app servers, caching and replicas for reads, and a very serious CDN and bandwidth strategy. But it's a different design for a company with a hundred times the users and, presumably, a hundred times the resources. Building it now, for a few hundred users, would mean paying the complexity cost for years before getting any benefit. Estimation tells you when to build what.

Step 14 of 14 · 1 min

Further reading

  • Jeff Dean's talks on designing large systems include his classic estimation examples (search for "Jeff Dean back of the envelope").
  • Your cloud provider's pricing pages for storage and data transfer, the real inputs for any cost estimate.
  • The Art of Capacity Planning by John Allspaw, written from his experience running Flickr's infrastructure.
  • Luke Stone, "Bringing Pokémon GO to life on Google Cloud," Google Cloud blog, 2016. The source of the 1×, 5× and 50× figures.
  • Mor Harchol-Balter, Performance Modeling and Design of Computer Systems, chapters on M/M/1 and M/M/k. The pooling result is in the M/M/k chapter.