Book Deep Read · System Design Interview Vol 1 · Ch 1
System Design Interview: An Insider's Guide · Vol 1 · Ch 1 · Alex Xu · 2020
Whatever website or app you have open right now almost certainly started as one machine somebody rented. This chapter is about how that single machine grows into a whole server room. It opens Volume 1 of System Design Interview, and it is the only chapter in the book that designs no particular product. What it gives you instead is a route: on the way from zero to a few million users, what to change, and in what order.
Think of a website as a noodle shop. On opening day the owner does everything alone: take orders, cook, take payment, keep the ledger. Business booms — now what? The instinct is "hire a better owner." The real answer is division of labour: put a host at the door, add burners in the kitchen, pre-cook the popular dishes and keep them warm, hand a copy of the ledger to an accountant, pin delivery tickets to a wall for couriers to grab, and finally open branches across town. Every scaling step in this chapter maps onto one of those.
When one machine stops coping, the cheap move is to buy a bigger machine. That road runs further than most people think — Stack Overflow served over two hundred million requests in a single day in 2016 on nine web servers and four databases. But it has one problem you cannot dodge: if that machine breaks, the site is simply gone. There is no substitute. So the real turning point is not "stronger" but "more" — a pile of ordinary machines, where losing one bothers nobody.
① Put a host at the door. Guests no longer walk up to a particular waiter; the host sends them to whoever is free. When a waiter calls in sick, guests are still served.
② But waiters must not "remember" guests. If the order you placed with waiter #3 lives only in his head, you have to order again the moment his shift ends. Write "who ordered what" into one shared book at the front desk instead, and any waiter can pick you up — this is the master switch for adding and removing staff freely.
③ Copy the ledger. Far more people read the books than write in them. Let writes go only into the original and reads go to the copies; the original instantly gets easier.
④ Pre-cook the popular dishes. The best sellers do not need making from scratch every time — that is caching. Photos and videos go further: keep a copy in every city and serve whichever is nearest.
⑤ Turn slow work into tickets on a wall. Photo editing, sending notifications — do not make the guest wait. Write a ticket, drop it in the queue, let the kitchen work through it, and add cooks when it backs up.
⑥ Only when it truly will not fit, split the ledger. One book is full, so split it into four by surname. This is the last step, and the only one you can barely walk back: once split, things that used to be a single lookup ("sort every guest by first visit") suddenly become painful.
The six are ordered by return on effort: the early ones are cheap, reversible and fast-acting; the last is expensive and hard to undo. So the question worth asking is never "what technology should we adopt," but "which part gives out first?"
Scaling is not "buy a bigger machine." It is repeatedly moving the thing that gets remembered out of wherever it is blocking you: out of the waiter's head (stateless), onto copies (read replicas), closer to the guest (caching and edge delivery), into a queue (async) — and only then splitting it up (sharding).
Want the mechanisms, the numbers and the diagrams? → Switch to the deep read
You think this chapter teaches you how to make a system big. What it actually teaches is an order. Load balancers, caches, CDNs, shards — those parts are documented everywhere. What this chapter contributes is arranging them into a build sequence with falling returns and rising irreversibility, where each step removes exactly one bottleneck. Get the order wrong and you pay permanent complexity for a problem you do not have yet.
This is the first of the three chapters in Volume 1's Part I on method and fundamentals, and the only chapter in the book that designs no product. Ch 2 teaches you to get QPS, storage and bandwidth right to an order of magnitude on a whiteboard; Ch 3 teaches the four-step interview framework; Ch 1 first supplies the shared skeleton both of those operate on. The twelve case studies that follow — rate limiter, URL shortener, news feed, YouTube, Google Drive — are almost all additions to one layer of that skeleton.
Ask an engineer "how many users can your system take" and the usual answer is a menu of names: we run Redis, Kafka, sharded databases. Names cannot answer why now, and why this one. What this chapter answers is a different question: which thing gives out next, and whether the money and complexity it costs are worth it.
What goes wrong otherwise? Too early: five thousand users and you already run microservices, sharded databases and multi-region, so eighty percent of the team's time goes into infrastructure rather than product — and sharding is essentially not refundable. Too late: you only think about read replicas once your one database is pegged at 90% CPU, and now every change has to be made under live production traffic, at maximum risk.
An anchor with real numbers: a content community with 1M daily actives, each opening the app 10 times a day and pulling 20 items per open. That is roughly 10M reads/day, about 116 QPS averaged out, and 350–600 QPS at peak if peak runs 3–5× the mean; writes are around one percent of reads. At that level one decent server plus one database genuinely still copes — what breaks first is not "volume" but one particular kind of request (the home-feed query joining three tables) and having no substitute. Which is exactly why the first move is usually a load balancer and a replica, not a shard.
The starting shape: one server running the web app, the database and the cache together. A user types a domain → DNS returns the IP → the browser connects directly → the server returns HTML or JSON. Look at this path first, because every later step is essentially inserting one more hop into it — a load balancer, a cache, a CDN, a queue. Miss the path and all you can do is memorise part names.
The first real separation is moving the database off the web server: the two want fundamentally different resources — web wants CPU and concurrent connections, databases want memory and disk I/O — so together they fight, and neither can scale on its own. On database choice the book's rule is plain: default to a relational database (RDBMS), and only consider NoSQL when you need very low latency, the data is unstructured, no complex queries are required, or the volume is enormous — never pick it because it sounds more modern.
Vertical scaling means a beefier single box. Its upside is badly underrated: it is simple — the application barely changes and you face none of the distributed-systems tax. It has two problems: a hard ceiling, and no failover, no redundancy. The second is the decisive one. Plenty of teams believe they went horizontal because they were not fast enough; what actually forced them was not daring to run on one box.
Horizontal scaling is a pile of ordinary machines with a load balancer in front. The LB owns the public IP and is all the client knows; the web servers behind it have private IPs only and talk over the internal network, never exposed directly. Two payoffs: when one dies, the LB sends traffic to the rest; when traffic grows, you add machines to the pool.
Adding web machines is easy because they store nothing. Databases are not so lucky. The first move is replication: one primary takes every write, while several replicas hold copies and serve reads only.
It pays off because nearly every application reads far more than it writes — the community above runs about 100:1. Spread reads over N replicas and read capacity grows close to linearly, while the application changes in exactly one way: reads to replicas, writes to the primary. You also get durability and availability for free (a dead replica means reads go elsewhere; a dead primary means promoting a replica).
The honest cost: replication is usually asynchronous, so replicas lag. If the request right after a user posts happens to land on a replica that has not caught up, they will not see their own post. The usual remedy is to pin that user's reads to the primary for a short window after a write.
The cache tier is a separate in-memory store (Redis, Memcached) between web and database. The common pattern is cache-aside: check the cache, return on a hit; only on a miss do you query the database, write the result back, and return it.
One number explains why it works: reading from memory is microseconds, while a network round trip plus a database disk lookup is typically milliseconds — three orders of magnitude. At a 90% hit rate the read load reaching the database drops to one tenth: the community peaking at 600 QPS leaves only 60 QPS hitting the database.
The book's five considerations each correspond to a class of production incident. When to use it — only data that is read often and changed rarely is worth caching, and a cache is not durable storage; a restart empties it. Expiry (TTL) — too short and you may as well not have one, too long and the data goes stale. Consistency — cache and database are not updated in one transaction, so a window of disagreement is unavoidable. Single point of failure — with one cache server, losing it sends every read to the database in the same instant and usually kills it, so spread across several and leave headroom. Eviction — when it is full, who goes? LRU (least recently used) is the default, with LFU and FIFO as alternatives.
A CDN is the same idea on a different axis: push static content out to edge nodes worldwide so users fetch it nearby. Caching saves backend computation; a CDN saves intercontinental round trips — a US-to-Asia round trip is typically 150–200 ms, and an edge node cuts that to low tens of milliseconds. Its pitfalls are just as concrete: you pay per byte served, so cold content on a CDN is pure waste; TTLs must match how often content changes; and updates only propagate via an invalidation API or a versioned URL (?v=2).
Saying "adding web machines is easy" quietly assumed something: a web server holding session data cannot be swapped out freely. The stateful version keeps user A's session in the memory of server 1, so every one of A's requests must be routed back to server 1 — a sticky session. The consequences chain: the LB's scheduling is nailed down, server 1 dying logs A out, and every scale event drops a batch of users. Autoscaling is simply off the table.
The fix takes one sentence but carries enormous weight: move sessions into a shared persistent store and let the web servers remember nothing. Now any box serves any request, and machines go from being assets with identities to disposable, freely replaceable resources. Every elastic capability that follows — autoscaling, multi-region, canary and blue-green releases — depends on this step. If you take one thing from this chapter, take this.
Multiple data centres: geoDNS (DNS that resolves one domain to different IPs by the user's location) sends users to the nearest site, cutting latency and letting you drain traffic away when a whole site fails. The book names three difficulties in passing, and each is hard: traffic redirection (geoDNS changes are subject to DNS caching, so they do not take effect the moment you flip the switch), data synchronisation (keeping sites consistent — the hardest of the three), and test and deployment.
Message queues: producers post tasks, workers consume them asynchronously, and the value is decoupling. The book's example is photo processing — the user uploads, the web server drops "crop, sharpen, blur" into the queue and returns success immediately, and workers grind through it behind the scenes. The real gain is that the two sides scale independently: add workers when the queue backs up, remove them when it empties, with no effect on the web tier.
Only when the database outgrows a single machine does sharding arrive: split one big table horizontally by a sharding key — the book's example is literally user_id % 4. The sharding key decides whether load is even, which makes it the most consequential and least revisable decision here. Three new problems come with it:
1/N.So the conclusion of this section is not "how to shard" but "finish everything cheaper first, then consider sharding."
Past a certain size, invisible means unfixable. The book gives three levels of metrics: host level (CPU, memory, disk I/O), aggregated level (database tier performance, cache hit rate) and business level (daily actives, retention, revenue), plus centralised logging and automation. It is the step that turns everything above from "it runs" into "it keeps running."
Table 1 · The scaling ladder: which bottleneck each step removes, what it costs, whether you can walk it back
| Step | Bottleneck removed | Typical gain | Cost | Reversible? |
|---|---|---|---|---|
| ① Split web and DB | Two resource profiles fighting | Each tier scales alone | One extra network hop (sub-ms) | Easily |
| ② LB + many web boxes | Single point of failure; web CPU | Web tier scales near-linearly | One more component to operate | Easily |
| ③ Make web tier stateless | Sticky sessions freezing scheduling | Unlocks autoscaling / multi-region / canary | One hop for session reads and writes | Easily |
| ④ Read replicas | Read load; only one copy of the data | At 100:1 read/write, reads scale near-linearly | Replication lag — you can read stale data | Easily |
| ⑤ Cache + CDN | Repeated queries; intercontinental RTT | 90% hit rate → DB reads at 1/10; RTT from 150ms+ to low tens of ms | Consistency window; a dead cache tier can kill the database | Easily |
| ⑥ Queue + workers | Slow tasks holding the main path | Instant response; both sides scale alone | Eventual consistency; retries and duplicates | Moderately |
| ⑦ Shard the database | It no longer fits on one machine | Storage and write capacity keep scaling | Hot keys, resharding, cross-shard joins | Barely |
Table 2 · Cache / CDN / replica: all three keep an extra copy — what differs is what they store and what they save
| Cache | CDN | Replica | |
|---|---|---|---|
| Stores | Query results, hot objects | Static files (images / JS / video) | A full copy of the database |
| Saves | Backend compute and DB queries | Cross-region round trips | Read load on the primary |
| Freshness | Depends on TTL and invalidation | Worst — TTLs often in hours or days | Best — lag usually ms to seconds |
| If it dies | Most dangerous: all reads hit the DB at once | Falls back to origin — slow, not fatal | Reads move to the primary or another replica |
This chapter became the standard opening of system design interviews because it hands you a route you can recite. Asked "what if traffic grows ten times," the bad answer is a menu of names; the good one is: "look at which tier gives out first — if web CPU is saturated, add machines; if database reads are, add a cache and replicas; only when one machine can no longer hold the data do we discuss sharding." Being able to say, at each step, "here is where I am stuck, so here is what I add" wins most of the interview and most of the design review. And the route has a public record on both sides:
209,420,973 HTTP requests, 66,294,789 of them page loads, on 9 primary web servers and 4 SQL Servers; he also writes that they are "down to needing only 1 web server," and have "unintentionally tested this, successfully, a few times" — counter-evidence: vertical scaling plus serious optimisation goes much further than people assume, and plenty of products never need a shard. N. Craver, "Stack Overflow: The Architecture — 2016 Edition" ↗① This chapter is not a parts list, it is a build order: each step removes one bottleneck, with falling returns and rising irreversibility.
② The first separation is pulling the database off the web server; default to a relational database, and reach for NoSQL only when very low latency, unstructured data, no complex queries and enormous volume all apply.
③ The real reason to go horizontal is not "not fast enough" but "not willing to run on one box" — the single point of failure is the turning point.
④ Statelessness is the master switch: with sessions in a shared store, machines stop being assets with identities and become disposable, and autoscaling becomes possible.
⑤ When reads dominate, the cheapest lever is replication; the price is replication lag — a user may not see what they just wrote.
⑥ Caching saves backend compute, a CDN saves intercontinental round trips; the cache tier is the most dangerous single point, since losing it dumps every read on the database at once.
⑦ A message queue buys decoupling and independent scaling: slow work goes in the queue and returns immediately; add workers when it backs up.
⑧ Sharding comes last, and brings resharding, celebrity hot spots and cross-shard joins with it — and you can barely walk it back.
⑨ Finish with logging, three levels of metrics and automation — without them, everything above merely runs rather than keeps running.