Course outline · 0% complete

0/29 lessons0%

Course overview →

Back-of-envelope numbers

lesson 9-1 · ~12 min · 25/29

The formula that turns daily traffic into load

Requests per day divided by 86,400 seconds gives average requests per second.

From lesson 1-1, that quotient is the average RPS, and then you multiply by a peak factor to get the number capacity is sized against. Both steps are required, since the average alone is the figure that produced the 8 pm crashes.

In interviews you round 86,400 to 100,000, meaning 10⁵, because clean mental division matters more than the last 15% of precision. Dividing by 100,000 is moving a decimal point, and the answer is 15% low in a consistent direction you can name out loud.

The one useful landmark to carry is that a million requests a day is about 12 per second. Anchoring to that lets you sanity-check any estimate in a second without arithmetic.

The numbers to memorize

Back-of-envelope estimation runs on a handful of memorized constants. One more term joins them, because interviewers use it in the first sentence of nearly every prompt: DAU, daily active users, the number of distinct users who open the product on a typical day. "Design this for 10 million DAU" hands you the seed number every other estimate grows from. These are the constants that pay rent:

FactValue
Seconds in a day86,400 ≈ 10⁵
Seconds in a year≈ 3.15 × 10⁷
1 KB / 1 MB / 1 GB / 1 TB10³ / 10⁶ / 10⁹ / 10¹² bytes
A tweet-sized record100 to 300 bytes
An image100 KB to 1 MB
Cache or memory readunder 1 ms
Database read10 to 50 ms
Same-region network hop1 to 2 ms
Cross-ocean round trip≈ 100 ms

And the method, unchanged since lesson 1-1: daily volume → per-second average → peak (× 5 or 10), plus record size → storage per day → storage per year. Round hard at every step. The goal is the right power of ten, because that is what picks the architecture.

A full write-side estimate

Ten million DAU, two posts each, 300 bytes per post, peak factor 5.

dau = 10_000_000
posts_per_user = 2
bytes_per_post = 300
SECONDS_PER_DAY = 86_400

writes_per_day = dau * posts_per_user
avg_writes_per_sec = writes_per_day / SECONDS_PER_DAY
peak_writes_per_sec = avg_writes_per_sec * 5
storage_per_day_gb = writes_per_day * bytes_per_post / 1_000_000_000

print("Writes per day:", writes_per_day)
print("Average writes/sec:", round(avg_writes_per_sec))
print("Peak writes/sec:", round(peak_writes_per_sec))
print("New storage per day (GB):", storage_per_day_gb)

Output

Writes per day: 20000000
Average writes/sec: 231
Peak writes/sec: 1157
New storage per day (GB): 6.0

Read the conclusions rather than the digits. Roughly 1,200 peak writes per second fits a single SQL leader from unit 4, and 6 GB a day is about 2 TB a year, which is easy storage.

Those two sentences are the actual deliverable of an estimate. The architecture question was whether this needs sharding, and 1,200 writes per second answers no, which saves the entire unit 5 discussion.

Naming the ceiling you are comparing against is what makes the conclusion credible. A single Postgres leader handles somewhere in the low tens of thousands of writes per second, so 1,200 is not close, and saying that number out loud shows the comparison is real.

The variables are named rather than inlined so each assumption is visible and challengeable. An interviewer who says users post ten times a day changes one line, and every downstream number follows.

Note that all four inputs are guesses, and that is fine. Estimation aims at the right power of ten, so a posts-per-user figure that is wrong by a factor of two does not change the architectural conclusion at all.

The read side

Same app, with reads outnumbering writes 100 to 1.

dau = 10_000_000
posts_per_user = 2
read_ratio = 100
SECONDS_PER_DAY = 86_400

writes_per_day = dau * posts_per_user
reads_per_day = writes_per_day * read_ratio
avg_reads_per_sec = reads_per_day / SECONDS_PER_DAY

print("Reads per day:", reads_per_day)
print("Average reads/sec:", round(avg_reads_per_sec))
print("Peak reads/sec:", round(avg_reads_per_sec * 5))

Output

Reads per day: 2000000000
Average reads/sec: 23148
Peak reads/sec: 115741

Two billion reads a day against twenty million writes is the number that shapes the design. The write side fit on one leader comfortably, and the read side does not fit on anything without help.

The 100-to-1 ratio is the most important assumption in the whole estimate, and it is worth stating as an assumption. Social feeds are read-heavy, and an interviewer may push back with a different ratio, which is a conversation rather than a correction.

115,741 peak reads per second is where units 3 and 4 become mandatory rather than optional. This is the moment in an interview to say the system is read-heavy, so it needs replicas or a cache, and probably both.

Note that the peak factor is applied to reads too, and it may not be the same factor. Reads and writes often peak together on a social app and can diverge elsewhere, since a news site sees reading spikes with no matching write spike.

A year of storage growth

Six gigabytes a day, extended to a year.

storage_per_day_gb = 6.0
days_per_year = 365
storage_per_year_gb = storage_per_day_gb * days_per_year
print("New storage per year (GB):", storage_per_year_gb)
print("New storage per year (TB):", round(storage_per_year_gb / 1000, 2))

Output

New storage per year (GB): 2190.0
New storage per year (TB): 2.19

The conclusion to say out loud in an interview is that about 2 TB a year fits comfortably in one replicated SQL database from unit 4. Storage is not the constraint for this product, which means the design conversation belongs on the read path.

Both units are printed because each has an audience. Gigabytes per year is what you compute, and terabytes is what people compare against disk sizes, so converting saves the listener a step.

Dividing by 1000 rather than 1024 is deliberate throughout this course, following the table in the constants block. It is the convention disk manufacturers and cloud providers use, and the 2.4% difference never matters at estimate precision.

The number is also low because posts are 300 bytes. Add images at 500 KB each and the same traffic produces several terabytes a day rather than a year, which is a completely different architecture built around object storage and a CDN.

That contrast is the useful lesson from this block. The record size is the input that decides whether storage is trivial or dominant, so it is the first thing to ask about when the prompt involves media.

Sizing the read tier before caching

ceil(115,741 / 15,000) = 8 replicas.

You cannot run 0.7 of a replica, so 7.7 rounds up to 8. In practice you would run 9 for the N+1 reason from lesson 2-3, since eight at full load means one failure overloads the rest.

Now watch the estimate drive design. A unit 3 cache at a 90% hit rate cuts database reads to about 11,600 per second, which is one replica's worth of load.

ConfigurationDatabase reads/secReplicas needed
no cache115,7418
90% hit rate11,5741
99% hit rate1,1571

This is the entire point of estimation, because the numbers tell you whether you need 8 replicas or 1 replica and a cache, before you build either. The cache is also cheaper and faster than the replicas it replaces, so the arithmetic points at the better system rather than merely a smaller one.

Note the risk that table hides, and it is worth volunteering in an interview. The single-replica design depends on the cache staying warm, so a cache restart drops the system to the top row instantly, which is the thundering herd from lesson 3-2 and an argument for keeping more replicas than the arithmetic demands.