This chapter is the compression: forty-six transferable rules of large-scale system design, extracted from the twenty-eight worked problems that produced them. The track is twenty-nine chapters; this one carries no problem of its own.
A rule is one line: a mechanism, plus the number that makes it true. For example: database load falls as (1-h), where h is the fraction of reads the cache answers, so each additional nine of hit rate divides database load by ten.
That rule has three parts: a mechanism (caching), a number (1-h), and something you can act on (the last few points of hit rate are worth more than the first thirty). Every row in this chapter’s rule tables has the same three parts. It is the rule, not the problem it came from, that transfers to a design question no chapter covers.
What you should be able to do when you finish. Name the pattern an unfamiliar problem belongs to, quote the arithmetic that decides it, and state which of your own assumptions the answer rests on.
Input and output. In goes a system design problem you have not seen, described in a sentence or two: “design a concert ticketing system”, “design a ride-hailing dispatcher”. Out comes a short, defensible chain:
- Five numbers, written down before anything else.
- One fork, taken because of the first of those numbers.
- Three independent checks, run in every case.
- A named architecture, with the binding constraint stated explicitly.
Worked the chart applied to a problem with no chapter runs that chain end to end on concert ticketing, from the arithmetic to the architecture.
Every idea this chapter uses is defined here before it is used. Follow a link when you want the derivation with its numbers; you should not need to follow one to understand a sentence on this page. The vocabulary everything else is written in defines the terms of art up front.
This chapter sits at the seam of the study plan. Chapters 01-15 are Volume 1. 17 through 29 are Volume 2. 1b volume 2 as twenty five more and Volume 2 the binding constraints are written to be useful both before you read Volume 2 and after.
Read it once now. Re-read Which pattern does this smell like and The numbers you cannot recompute under pressure the morning of the interview.
0. The vocabulary everything else is written in
Every term of art the rest of the chapter uses is defined here in plain English. Using a mechanism’s name without being able to define it is a common way to sound like you do not understand it.
Read it once, then treat it as a lookup table: jump back here whenever a later section uses a word you cannot define.
Terms about the systems themselves
- A node or box is one server. A fleet is however many of them a service runs on. RAM is random-access memory, the fast working memory a program computes out of, as opposed to disk.
- QPS is queries per second: how many requests a second the system handles. Offered load is the rate arriving; service capacity is the rate the system can absorb. They are different quantities that share a unit, which is the source of the single most common arithmetic mistake in this round.
- Latency is how long one request takes. p99 is the ninety-ninth-percentile latency — the time that 99 requests out of 100 come in under — so it describes the slow tail rather than the typical case. p99.9 is the same idea one decimal place further out: the time 999 requests in 1,000 beat. It matters because a request that has to wait on ten machines inherits a tail well past any one machine’s p99. RTT is a round trip time: request out, response back.
- Throughput is work per unit time; headroom is the gap between capacity and offered load, and it is what determines how fast a backlog drains.
- Utilization, written
rho(the Greek letter rho), is offered load divided by capacity. Queueing delay grows asrho / (1 - rho), which is why a system at 90% utilization waits nine service times and a system at 50% waits one. - CV is the coefficient of variation — the standard deviation divided by the mean — which is the right way to express load imbalance across machines because it is unitless and so compares across fleet sizes.
- Blast radius is how much of the system one failure takes down with it, which is why fleets are sized by the damage one lost machine does and not only by capacity.
- A DAG is a directed acyclic graph: a set of steps with dependencies between them and no cycles, which is the natural shape of a processing pipeline such as video transcoding.
- HTTP status codes appear as shorthand: 409 means Conflict — your write lost a race — and 429 means Too Many Requests, the polite way for a server to shed load.
Terms about storing and finding data
- Sharding or partitioning means splitting one dataset across several machines by some key, so that each machine holds a slice. The shard key is the column whose value decides which machine a row lives on. Replication means putting identical full copies on several machines. Sharding buys capacity; replication buys read throughput and survivability.
- The working set is the data actually touched by live traffic, which is usually far smaller than the data stored. It is the number that decides whether you need to shard at all.
- A scatter-gather query is one that has to ask every shard and combine the answers, which makes its latency the slowest of the responses.
- A hot key is a single key that receives a disproportionate share of the traffic. Partitioning cannot help it, because one key hashes to one place by construction.
- A cache is a fast copy of data in front of a slower store. The hit rate
his the fraction of reads the cache answers;(1-h)is the fraction that fall through. An LRU cache is a least-recently-used cache: when it is full, it evicts whatever has gone longest without being read. A TTL is a time to live, the age at which a cached copy must be discarded. - Zipfian describes an access pattern where a small number of items get most of the requests — the shape of nearly all real-world popularity.
- A CDN is a content delivery network: caches placed physically near users so a request does not have to cross an ocean.
- Cardinality is how many distinct values something has. In a monitoring system, a label with unbounded cardinality is one whose set of possible values grows with traffic, which is why one label can multiply your storage bill by four orders of magnitude.
- A KV store is a key-value store: a database whose only operations are “put this value under this key” and “get the value at this key”. A B-tree is the classic index structure a relational database uses, kept sorted and updated in place. An LSM tree is a log-structured merge tree, the alternative that buffers writes in memory and writes whole sorted files out, merging them in the background — which is why it beats a B-tree on write-heavy workloads.
ZREVRANKis the Redis command that returns an item’s position in a sorted set. It is named here only because reaching for it is the reflex answer to a leaderboard question, and it does not shard.
Terms about correctness when there is more than one machine
- A quorum is a required number of replicas that must agree. In a store with
Nreplicas,Wis how many must acknowledge a write andRhow many must be read;W + R > Nguarantees that any read overlaps any write. - A partition, in the network sense, is a break that leaves two halves of a system unable to talk. CAP is the observation that during one you must choose between remaining consistent and remaining available.
- Consistent hashing places keys on a conceptual ring rather than by
key mod N, so that adding or removing a machine moves the minimum possible fraction of keys. Virtual nodes are many small ring positions per physical machine, which evens out the load. - A version vector or vector clock is a per-writer counter set attached to an object, which lets you tell whether two versions are causally ordered or genuinely concurrent. It detects conflicts; it does not resolve them.
- A sibling is one of the concurrent versions such a detection leaves behind.
- Compare-and-swap is a write that only succeeds if the value is still what you last read — the cheap single-owner alternative to a version vector.
- Last-write-wins resolves a conflict by keeping whichever version has the later timestamp, silently discarding the other. It is data loss, not a policy.
- Idempotent means an operation can be applied twice with the same result as applying it once. An idempotency key is the client-supplied identifier that makes a retry safe.
- A Merkle tree is a tree of hashes over a dataset, which lets two replicas find their differing keys in
O(log n)comparisons instead ofO(n). - Anti-entropy is the background process that uses such a comparison to repair diverged replicas.
- 2PC is two-phase commit: a coordinator asks every participant to prepare, then tells them all to commit. A saga is the alternative — run the steps one at a time and undo the earlier ones with compensating actions if a later one fails.
- Linearizable means every read sees the most recent write, as if there were one copy.
- Eventual consistency is the opposite end of that scale: replicas are allowed to disagree for a while and are only guaranteed to converge once writes stop. It is what a quorum below
W + R > Nbuys, what Dynamo chooses and Spanner refuses, and the concept the whole contrast in Seven papers and the problem each one actually solved turns on.
Terms about streams, queues and time
- A queue or log carries messages between services. Backpressure is the mechanism by which a full downstream slows an upstream instead of collapsing. Admission control is the version of that decision made at the front door: let work in only at the rate the system behind can absorb, and turn the rest away immediately.
- An offset or cursor is a consumer’s read position in a log; owning it is what makes replay free.
- Consumer lag is how far behind the head of the log a consumer is.
- Event time is when something happened; processing time is when your system saw it. A watermark is the system’s declaration that it believes all events up to a given event time have now arrived.
- An upsert writes a row if it is absent and replaces it if it is present. An absolute-value upsert writes the running total (
= 47) rather than an increment (+= 1), which is what makes replaying the same message twice a no-op. - Restatement, or amendment, is publishing a corrected figure after you have already published a fast one. It is the alternative to waiting long enough to be right the first time.
- Fan-out is one input producing many outputs — one tweet becoming a million feed writes. Fan-in is the reverse.
- Jitter is deliberate randomness added to retry or reconnect delays so that clients do not synchronize into a stampede.
- Salting a key means appending a random suffix to spread one hot key across several partitions, then merging the parts.
Terms about storage economics, money and the rest
- RF 3, replication factor three, means three full copies, so 3x the bytes. Erasure coding, written RS(k, m) for Reed-Solomon, splits an object into
kdata fragments plusmparity fragments; anykof thek + mreconstruct it, which gives durability at(k+m)/ktimes the bytes — 1.4x for RS(10,4). - IOPS is input/output operations per second, the count of separate reads or writes a device can do. NVMe is the modern fast solid-state disk interface. Write amplification is the ratio between bytes the storage engine actually writes to the device and bytes the application handed it — a 50-byte row that costs 2,100 bytes of device writes is 42x amplified.
- A Bloom filter is a compact probabilistic structure that answers “is this item in the set” with no false negatives and a tunable false-positive (FP) rate, at about 9.6 bits per entry for 1%.
- A fold is the running result of applying an operation down a sequence — a balance is the fold of every entry in a ledger. Memoized means that result is cached rather than recomputed, so a memoized fold is a stored balance column that must be kept in step with the entries it summarizes.
- A blob store or object store holds arbitrarily large opaque byte strings under string keys, with no query language, no joins and no partial updates — S3 is the familiar example. Half of this track’s storage designs are a small mutable index in a database plus an enormous immutable byte pool in one of these.
- Content addressing means naming a blob by the hash of its bytes, so the name is the checksum and re-uploading the same content is automatically idempotent.
- Deduplication is storing one physical copy of bytes that appear in many logical places. It saves storage always and bandwidth only if the client is told what the server already holds — which is the version that leaks, because that answer is a question about other people’s data.
- CDC, content-defined chunking, cuts a file at boundaries determined by its contents rather than at fixed offsets, so inserting a byte does not shift every chunk.
- GC is garbage collection: the sweep that deletes data nothing references any more.
- Double-entry bookkeeping records every movement of money as equal and opposite entries, so a correct ledger sums to zero per currency and a half-written transfer has no representation at all.
- An SLO is a service level objective, a target such as 99.9% success. The error budget is the allowance it implies — 0.1% of requests — and burn rate is how fast you are spending it.
- Determinism means the same inputs always produce the same outputs, in the same order, with no dependence on wall clock, floating point, hash iteration order or thread scheduling. It is what makes a standby able to replay a log and get the identical state.
Two names for people and services appear repeatedly: APNs is Apple’s push notification service, and a PSP is a payment service provider — the company that actually talks to the card networks on your behalf.
1. Volume 1 as twenty-one rules
The first of the two rule tables: twenty-one mechanisms from Volume 1, each with the chapter that derives it and the one line you should be able to say about it without preparation.
The one-line rule is the deliverable: if you can state it without looking, you know the mechanism. The name and source are the handle to reach for in an interview and where to check the arithmetic; nobody will ask you to recite them.
| Pattern | Derived in | The rule, in one line |
|---|---|---|
| Estimate first | 02 | The output is not a number, it is the name of the binding constraint. If the answer would not change the design, do not compute it |
| Cache | 01, 08 | Latency is linear in hit rate; database load falls as (1-h), so each additional nine divides it by ten. The last few points are worth more than the first thirty |
| Read replicas | 01 | Buys read throughput, costs read-your-writes. Route a writer’s own reads to the primary for one RTT afterwards |
| Shard last | 01 | Six cheaper things come first. When you do shard, the key must be the one reads already use, or every query is a scatter-gather |
| Consistent hashing | 05, 05 | mod N moves 94% of keys on a resize; a ring moves 1/(N+1), which is optimal, not merely small |
| Virtual nodes | 05 | V buys variance, not mean: load CV falls as 1/sqrt(V). The fraction that moves is 1/(N+1) at every V |
| Hot key | 05, 08 | Partitioning cannot help one hot key, by construction. An in-process LRU on every app node can |
| Quorum | 06 | W + R > N is the entire knob. It trades availability for consistency, and only during a partition |
| Causality | 06, 15 | Version vectors only when there is no single owner per object. With one owner, a compare-and-swap on an integer does the same job 120x cheaper |
| Conflict resolution | 15 | Last-write-wins is silent data loss, not a policy. Merge, keep both, or ask a human — and say which |
| Anti-entropy | 06 | Comparing two replicas is O(log n) with a Merkle tree and O(n) without. That is the difference between hourly and never |
| Queues | 01 | Anything off the user’s critical path goes async. The queue is not a buffer, it is where backpressure is allowed to live |
| CDN and edge | 01, 02 | Forced by bytes and by the 150 ms cross-continent RTT, never by QPS. At video scale, egress is the business |
| Rate limiting | 04 | A correctness control, not a cost control. Token bucket unless you can name why not |
| Backpressure and jitter | 04, 15 | An unjittered retry or reconnect is a denial of service you performed on yourself |
| Idempotency | 04, 08, 15 | Every retryable write needs a key. Content addressing gives you one for free: the name is the checksum |
| Unique IDs | 07 | Uniqueness and density are different products. A shortener needs density; a database needs uniqueness and sortability |
| Probabilistic filters | 06, 08 | 9.6 bits per entry at 1% false positives turns “is it in this 10-million-item set” into a memory reference |
| Delta and cursors | 15 | Ship what changed since a cursor, never the whole state. Resumability and idempotency come free with the sequence number |
| Coding vs replication | 02, 15 | RF 3 is 3x; RS(10,4) is 1.4x. On cold data that ratio is most of the storage bill |
| Two stores, no transaction | 15 | You cannot make them atomic, so order the writes so the survivable failure is the one that happens, and garbage-collect the debris |
If you can say fifteen of those twenty-one lines cold, you can hold a system design conversation about a problem nobody has written a chapter for.
Three Volume 1 rules, applied to a problem the track never covers
Some rows above carry their own worked instance, because the number is the instance — “94% against 1/(N+1)” is not abstract. Three rows are genuinely abstract, though, and they are the ones a first reader cannot picture. Here they are on a problem no chapter in this track contains: letting users attach photos to restaurant reviews.
Assume 3 million photos uploaded a day at 2 MB each, and 500 million review page-views a day. Every number below follows from those two.
“Estimate first” — the output is the name of the binding constraint, not a number. Run the arithmetic:
photo writes/s 3,000,000 / 86,400 = 34.7 /s
bytes/day 3,000,000 x 2 MB = 6 TB/day
bytes over 3 years 6 TB x 365 x 3 = 6.57 PB
read : write 500,000,000 / 3,000,000 = 167 : 1
Thirty-five writes a second is nothing; a single database absorbs it without noticing. The constraint is bytes, not requests — 6.57 petabytes over three years, of data nobody edits after upload. That single sentence is what the estimate was for. It tells you the interview is about storage tiering and erasure coding, and that any minute spent on write throughput is a minute wasted. The 167:1 ratio then tells you the read path is a caching and CDN problem, which is the second thing worth knowing and not the first.
“Queues” — anything off the user’s critical path goes async. The user’s upload must return as soon as the bytes are durable. Everything after that — generating thumbnails, running the content-safety scan, extracting the location tag — is work the user is not waiting for, so it goes on a queue. The rule’s second half is the part people miss: the queue is not there to smooth out a spike, it is there so that when the thumbnail workers fall behind, the backlog has somewhere legitimate to sit instead of pushing latency back into the upload call. If the thumbnail fleet dies for an hour, uploads keep succeeding and thumbnails appear late. That is the whole reason the queue exists.
“Two stores, no transaction” — order the writes so the survivable failure is the one that happens. The photo bytes go in a blob store and the review row goes in a database, and there is no transaction spanning the two. So write the bytes first, then commit the row. If the process dies in between you have paid for bytes nobody references — an orphan — which a background sweep can find and delete. Commit the row first and a crash leaves a review pointing at a photo that does not exist, which the user sees as a broken image and which no sweep can repair. Same two writes, opposite failure, and the only thing you changed was the order.
1b. Volume 2 as twenty-five more
The second rule table is organized around a different question. Volume 1 answers how do I build the mechanism. Volume 2 mostly answers which constraint is actually binding, and what does the honest version of this cost.
The columns work exactly as in Volume 1 as twenty one rules: name, source, deliverable. Read the table once before chapter 17 as a preview and once after chapter 29 as recall; the rows are written to work both ways. On the first pass, a row you cannot picture is a row whose chapter you have not read yet — that is expected, and the second column tells you where to go.
| Pattern | Derived in | The rule, in one line |
|---|---|---|
| Flattening 2-D into 1-D | 17, 17 | A B-tree is one-dimensional and a query disc is not. Every cell scheme is a candidate generator, and the exact distance test is always the last gate |
| Bounded vs unbounded candidates | 18 | Index space only when the candidate set is unbounded. A 200-element friend list is a 20 us scan that returns exactly the right set and leaks nothing |
| Precompute what does not move | 19 | Split an artifact by its rate of change. Topology changes when a road is built; the metric changes every two minutes, and only the cheap half may be recomputed at the fast rate |
| The log, not the queue | 20 | Give the read position to the consumer and the broker’s job collapses to appending bytes. Replay and a second consumer group then cost nothing |
| Headroom, not throughput | 20 | Recovery time is backlog / (capacity - offered load). A fleet sized at exactly its load never drains, at any throughput |
| Cardinality, not volume | 21 | A label is legal only if its value set is bounded and does not grow with traffic. One unbounded label is 2,134x the fleet, and the pull request was one line |
| Symptoms, with a derived threshold | 21, 21 | A per-series threshold’s false-positive rate scales with fleet size; burn rate against an error budget scales with incidents. 14.4 = 0.02 x 720 is arithmetic, not folklore |
| Shed at the door | 21 | A queue whose wait crosses the sender’s timeout raises the arrival rate. Reject where the backlog already has a home, and shed new work before work something depends on |
| Event time, and restatement | 22, 22 | Price both sides of the wait. When the best single watermark still misses the target, close fast and amend — and emit absolute values so a replay is a no-op |
| Salt the provably hot key | 22 | A ring cannot split one key, so change the key. Salt only the keys above the uniform share and the merge stage is 512 rows/s, which a laptop runs |
| The check and the write are one step | 23 | UPDATE ... WHERE remaining > 0 beats every lock because the predicate runs under the lock that statement already holds. The defect is never “we forgot a lock” |
| Saga, not two-phase commit | 23, 28 | 2PC’s steady-state cost is mild and its failure is not: a dead coordinator leaves participants holding locks with no authority to release them |
| Compensation is not rollback | 28 | The intermediate state was visible, so order the fallible step first and make every later failure a retry rather than an apology |
| Pay the fan-out once, deliberately | 24 | Every subsystem either pays the fan-out or dodges it. Name which, per subsystem, instead of letting the multiplier land where it happens to |
| Isolation by partition, not by predicate | 24 | WHERE owner = me survives until someone writes a new code path. Another tenant’s data should not be in the structure being read |
| Erasure coding, and its actual bill | 25, 25 | 1.4x against 3x looks like a dominance. You pay in tail latency, because k fetches make the object’s p99 the fragment’s p99.9, and in small objects below k x block |
| Immutability is the design | 25, 28 | A parity update is a delta, so it is not idempotent. Refusing in-place writes is what makes every retry in the system safe, and a correction becomes a new entry |
| Accuracy is a function of position | 26 | The same absolute error is 500x wrong at rank 10 and invisible at rank 10 million. Exact at the head, bucketed in the tail, and say which one the caller got |
| Decomposable or not | 26 | Top-k is a selection and shards perfectly; rank is a global count and no per-shard statistic reconstructs it. Ask which one a query is before you shard |
| Double-entry | 27 | Every transaction sums to zero, so a half-written movement has no representation. It catches asymmetry and never duplication — that is idempotency’s job |
| Money is an integer | 27 | Minor units end to end, Decimal only for sub-unit intermediates, and every division redistributes its remainder so the parts sum to the whole |
| The unknown outcome | 27 | Commit the key before the external call, and on a timeout ask what happened rather than re-sending. Every unknown becomes a detected unknown with an owner |
| A balance is a memoized fold | 28 | The log is the truth and the column is a cache of it, written in the same transaction. Snapshot on a count of entries, never on a clock |
| Determinism | 29 | No wall clock, no floats, no hash iteration order, no allocation, one thread. Then a hot standby is not a protocol, it is the same program reading the same log |
| Utilization is a latency knob | 29 | Queueing delay is rho / (1 - rho) service times, so you shard a system with no throughput problem in order to choose a smaller rho |
One discipline runs underneath a third of that table and is worth stating on its own, because it is the single most common arithmetic mistake in this round:
State whether a rate is offered load or service capacity at the moment you derive it, and never divide one by the other without saying which is which. Both are measured in requests per second, which is why they get mixed up, and a design that divides one by the other produces a fleet size that is wrong by the ratio between them.
That discipline is stated in ch 03, spent on an ingest path in ch 18 and on partition counts in ch 20, and extended to fleet counts in ch 21, where the same rule applies to machine counts: compare capacity against capacity, or a high-availability configuration against a high-availability configuration, never one of each.
Three Volume 2 rules, applied to a problem the track never covers
Three rows above are stated as principles rather than as numbers, which makes them the hardest to picture. Here they are on a multi-tenant customer-support ticket system — many companies, each with their own agents, their own customers and their own tickets — which no chapter in this track builds.
“Pay the fan-out once, deliberately” — name which subsystem pays, per subsystem. One reply on a ticket has to reach several places: the agent’s inbox view, the customer’s email, the tenant’s analytics roll-up, and the full-text search index. Each of those either pays the fan-out — writing a copy per destination at reply time — or dodges it, by storing one copy and having each reader come find it.
The point of the rule is that you must decide this per subsystem and say so, not let the multiplier land wherever the first implementation happened to put it. Reasonable answer: the agent inbox dodges it (agents query by tenant, and the query is cheap); email pays it, because email is a copy by definition and there is no dodging available; analytics dodges it by reading the same log the inbox reads; search pays it, because an index entry per ticket is the only structure that answers a search fast. Two pay, two dodge, and you can defend each one. The failing answer is not “we fan out” or “we do not” — it is having no per-subsystem answer at all.
“Isolation by partition, not by predicate” — another tenant’s data should not be in the structure being read. The predicate version is one global ticket table with WHERE tenant_id = ? on every query. It is correct today and it stays correct only for as long as every future code path remembers the clause. One forgotten WHERE is a cross-tenant data leak, and no test that runs against a single tenant’s fixtures will ever catch it. The partition version gives each tenant its own index, so the other tenants’ rows are not in the structure the query reads at all. Then a forgotten filter returns fewer results, not somebody else’s. Access control by partition survives refactors that access control by predicate does not.
“Decomposable or not” — ask which one a query is before you shard. Two questions an agent dashboard asks look equally innocent:
- “Show me the 10 oldest open tickets.” This is a top-k selection. Ask every shard for its own 10 oldest, merge the results, keep the top 10. Each shard’s answer is a valid partial answer, so the query shards perfectly.
- “How many open tickets are older than mine?” This is a rank, which is a global count. No per-shard statistic reconstructs it — a shard can tell you how many of its tickets are older, and you only get the answer by adding up every shard, every time.
Same dashboard, same table, and one of the two queries silently becomes a scatter-gather across the entire fleet the moment you shard. The rule says to ask the question before you choose the layout, not after.
2. The twenty-eight problems, and what each one is actually for
Every problem in the track maps to the single mechanism it exists to teach and the single mistake it exists to catch — which is how to pick a chapter by what you need rather than by its title.
No chapter exists for its own sake. Each one is a delivery vehicle for one mechanism you would otherwise never derive, plus one thing candidates reliably get wrong, and compressing a chapter to those two things is the test of whether you read it or skimmed it.
The two tables below hold fifteen problems and thirteen, which is twenty-eight. This chapter is the one that carries no problem of its own.
Volume 1 — the mechanisms
These fifteen chapters each introduce a mechanism.
| # | Problem | What it exists to teach | The reliable mistake |
|---|---|---|---|
| 01 | Scale to millions | The ladder, and that sharding is the last rung, not the first | Sharding at step 1 |
| 02 | Estimation | An estimate names the binding constraint; the number is a by-product | Computing something that changes no decision |
| 03 | The framework | 45 minutes has a shape, and you pick the deep dive | Waiting to be told what to go deep on |
| 04 | Rate limiter | Four algorithms that differ only in exactly how wrong they are at a window boundary | Treating the client contract as an afterthought |
| 05 | Consistent hashing | 1/(N+1) against 94%, and that virtual nodes buy variance | “It minimizes reshuffling,” with no number |
| 06 | Key-value store | Leaderless replication end to end: quorum, siblings, Merkle repair | Claiming vector clocks resolve conflicts. They only detect them |
| 07 | Unique ID generator | A bit budget is a design decision, and clocks run backwards | Assuming a monotonic wall clock |
| 08 | URL shortener | Keyspace arithmetic, and that a short code is obscure but never secret | Picking a length with no arithmetic behind it |
| 09 | Web crawler | Politeness as a scheduling constraint, and that “dedup” means two unrelated things | Treating URL dedup and content dedup as one problem |
| 10 | Notification system | Routing as a cost lever, over a delivery path you do not own | Assuming your own delivery guarantees apply to APNs or a carrier |
| 11 | News feed | Fan-out on write against fan-out on read, and that the celebrity decides it | Picking one fan-out mode for the whole corpus |
| 12 | Chat | Connection tiers, per-conversation ordering, and delivery semantics | Sizing a socket tier by RAM |
| 13 | Search autocomplete | Rebuild beats update, and the client deletes most of the traffic | Designing a server for keystrokes the client should never send |
| 14 | YouTube | Transcoding as a DAG, and that egress is the business | Spending the interview on the player |
| 15 | Google Drive | Content boundaries against offset boundaries; two stores with no transaction between them | “We only sync the diff,” with no definition of a boundary |
Chapters 09 through 14 introduce almost no new mechanism. They recombine Volume 1 as twenty one rules’s list under different constraints — which is exactly the claim you are being tested on, that the mechanisms transfer.
Chapter 15 is the exception, and Volume 1 as twenty one rules’s own second column says so. You can check this yourself against the table above rather than taking it on trust.
Count the appearances of 15 in §1’s Derived in column: seven of the twenty-one rows. Now count the rows where 15 is the only citation: three — conflict resolution, delta and cursors, and two stores with no transaction. No other chapter is the sole source of more. Only chapter 01 matches it, with read replicas, shard-last and queues.
So the recombination claim has a boundary, and it is worth stating rather than smoothing over. The six problems before 15 are recombinations. Chapter 15 earns three rules of its own, by being the first problem in the track where two stores must agree without a transaction between them.
If a chapter contributes a rule nobody else derives, saying it introduced no new mechanism would leave three rows of §1 with no home.
Volume 2 — the binding constraints
These thirteen chapters mostly reuse those mechanisms and teach instead which constraint decides the design.
| # | Problem | What it exists to teach | The reliable mistake |
|---|---|---|---|
| 17 | Proximity service | Every geospatial index is a scheme for flattening two dimensions into one without losing locality | Querying one cell when the disc cannot fit inside one |
| 18 | Nearby friends | The same points, moving — which makes it a presence system with a payload, not a spatial problem | Durably storing a value that is wrong 30 seconds later |
| 19 | Google Maps | Precomputation beats search by 61,800x, and the precomputation must be split by rate of change | “Run Dijkstra,” with no cost estimate |
| 20 | Message queue | Chapter 01’s queue box, opened: it is an append-only file and the consumer owns the offset | Treating throughput as the health metric instead of d(lag)/dt |
| 21 | Metrics and alerting | The system is sized by active series, and an alert threshold is derived from an error budget | Adding a label, then paging on a per-series threshold |
| 22 | Ad click aggregation | Counting when the count is multiplied by a price and mailed to a customer | Believing a single watermark can be tuned to hit the accuracy target |
| 23 | Hotel reservation | Eight writes a second, and the entire interview is one race condition | A sharded pipeline for 8 writes/s, then a payment call inside the transaction |
| 24 | Distributed email | Where the fan-out lands, subsystem by subsystem, and what a per-user index buys | Storing a copy per recipient; “we add Elasticsearch” with no index sized |
| 25 | Object storage | A small mutable index against an enormous immutable byte pool, and what coding really costs | Quoting eleven nines as if it came out of a model |
| 26 | Gaming leaderboard | Top-k is a decomposable selection; rank is a global aggregate. Only one of them shards | Answering both with ZREVRANK and stopping |
| 27 | Payment system | The books, and the three seconds in which nobody knows whether the card was charged | Retrying the charge instead of asking what happened |
| 28 | Digital wallet | The same ledger with no third party, where one balance row does 1,333 writes/s | Assuming 2PC is fine because you own both shards |
| 29 | Stock exchange | Determinism inside a budget of 11.55 microseconds | Sharding the matching engine for throughput it does not need |
Volume 2 is organized by constraint rather than by mechanism, and three of its chapters are the corners of the space. Ch 23 is pure correctness at a scale that is a rounding error; ch 29 is the same correctness inside a microsecond budget; ch 25 is durability at exabyte scale where the budget is dollars per petabyte-month. Each of those three chapters says so about the other two. Placing an unfamiliar problem against those three corners is faster than pattern-matching it against a mechanism.
3. Which pattern does this smell like?
An architecture for a problem you have never seen can be chosen with one number rather than intuition — and the failure mode to prevent is reaching for a pattern before you have any numbers at all.
Everything below is keyed off five questions you should have asked and answered in the first eight minutes (ch 03):
- Read:write ratio — how many reads the system does per write.
- Consistency, field by field — what must be current, and what may be stale.
- p99 latency target, and where in the world the users are.
- Retention — how long the data must be kept.
- Growth — over two years.
Only the first of those five genuinely dispatches. “Dispatches” means it decides which further question you ask; the other four are checks you run in every case, and the gates below are where they land.
The chart reads top to bottom. You enter at the box that says write the five numbers down. You branch once, on the read:write ratio. Each branch asks one follow-up question, and you land in one of six leaves. Every leaf names an architecture and the chapter that prices it. There is nothing else in the chart — no components, no data flow, no arrows meaning “sends a request to”.
flowchart TD
A["Write the five numbers down FIRST<br/>read:write · consistency per field · p99 and where users are<br/>retention · growth (ch 03 step 1)"] --> B{"read : write"}
B -->|"under ~10:1"| W{"Is a write a NEWER VALUE<br/>or a NEW FACT?"}
W -->|"newer value,<br/>supersedes the last"| W1["One slot per key, overwritten.<br/>A 10-deep queue serves a fix 5 TTLs stale.<br/>ch 18 section 12"]
W -->|"new fact,<br/>must be counted"| W2["Append-only log, then windowed aggregation.<br/>Dedup key plus absolute-value upsert,<br/>never INCREMENT. ch 20, ch 22"]
B -->|"~10:1 to ~100:1"| M{"Does a small hot set<br/>cover most of the reads?"}
M -->|"yes, Zipfian"| M1["Cache-shaped after all.<br/>ch 08 at exactly 10:1 buys h = 0.962<br/>with 10 GB of RAM"]
M -->|"no, flat"| M2["Build both paths and say so.<br/>The middle band is a finding,<br/>not a failure to decide"]
B -->|"over ~100:1"| R{"Does ONE key carry a<br/>large share of the reads?"}
R -->|"no"| R1["Shared cache plus replicas.<br/>Each extra nine divides DB load by ten.<br/>ch 02 estimation 5"]
R -->|"yes"| R2["Hot key. In-process LRU, or replicate<br/>that one key everywhere. Partitioning<br/>cannot help: one key, one hash. ch 05"]
The six leaves in words
The chart is readable without squinting at it if you take the three branches one at a time.
Write-heavy, under about 10 reads per write. The follow-up question is whether a write is a newer value or a new fact.
- A newer value supersedes the last one — a position, a status, a current price. It goes into a single slot per key, overwritten in place.
- A new fact must be counted — a click, a payment, a trade. It goes into an append-only log and is aggregated in time windows afterwards.
The middle band, about 10:1 to about 100:1. The follow-up question is whether a small hot set covers most of the reads.
- Zipfian: the problem turns out to be cache-shaped after all. That is the leaf citing ch 08’s
h = 0.962. - Flat, meaning reads are spread evenly: build both paths and say so.
Read-heavy, over about 100 reads per write. The follow-up question is whether one key carries a large share of the reads.
- No: a shared cache plus read replicas.
- Yes: you are at a hot key, where partitioning is provably no help.
Why the chart has no colours
Every other diagram in this track uses chapter 01’s published key: blue is the authoritative copy of the data, green is read capacity, orange is a box forced by something other than processor time, and red is the one rung you cannot undo.
That key describes components. This chart has no components. Its boxes are a question, three more questions and six answers, so colouring them can only mislead: blue would land on the entry box, green on an append-only log that is itself the authority, orange on a cache, and red on a hot key, which is among the most undoable conditions in the book.
A decision chart is not an architecture diagram, and the key does not apply to it.
Five things the chart is deliberately saying
-
The first box is the whole trick. Every branch below it is decided by a number, and a candidate who has not written the numbers down is guessing at every fork. The most common way to lose this round is to arrive at “we’ll shard it” without ever computing whether one machine would have done.
-
The thresholds are ch 03’s, and they are asymmetric on purpose. Under about ten reads per write, the write path is the system; over about a hundred, caching stops being an optimization and becomes the design. The band between them is wide, and it is where most real problems land — including Worked the chart applied to a problem with no chapter’s ticketing example, at 12:1.
-
In the middle band the ratio has stopped being informative and the access distribution takes over. Ch 08 sits at exactly 10:1 and still comes out cache-shaped, because its reads are Zipfian — a small set of links gets most of the clicks. Ten gigabytes of memory buys a 96.2% hit rate there, meaning
h = 0.962, so only 3.8% of reads reach the database.A flat distribution at the same ratio buys nothing of the sort: a cache holding half the links would serve exactly half the reads, and more memory would not bend that line. Two systems with identical read:write ratios can want opposite architectures, and the tiebreak is a second number, not a stronger opinion.
-
The write-heavy fork is the one candidates have never rehearsed, and it splits cleanly on a single question: is a write a newer value or a new fact?
If a write supersedes the last one — a position, a status, a current price — then buffering it is actively wrong, because a buffer’s whole job is to preserve things you no longer want. Ch 18 shows a ten-deep queue delivering a location fix five TTLs past its own expiry date, and derives that the correct queue depth is one.
If instead a write is a new fact that must be counted — a click, a payment, a trade — you are in ch 20 and ch 22. The write must then be an absolute-value upsert: store the running total (
= 47), not the increment (+= 1), so that replaying the same message twice changes nothing. -
The read-heavy fork ends at the hot key on purpose. A hot key is the one place where adding machines is provably no help (ch 05), because one key hashes to one partition no matter how many partitions exist, and it recurs in five separate chapters (Seven failure shapes which is all of them).
The three gates the chart deliberately does not contain
The remaining three questions do not branch, so they are not in the chart. They are independent gates: checks that either fire or do not fire, in any of the six leaves above. A gate that fires changes the design regardless of which leaf you landed in.
Drawing them as further levels of a tree would make a flat checklist look like a decision procedure, when only the read:write node in that tree actually carries a number. Run them as a list, every time, in every problem.
Each gate below is a yes-or-no question, the number you check it against (with the chapter that derived it), and what changes in the design when the answer comes back yes.
| Gate | The number that decides it | If it fires |
|---|---|---|
| Does the working set — the data actually touched by live traffic — fit in one machine’s memory? | Default to a 128 GB commodity box and say so (ch 02). Every business on Earth is 60 GB (ch 17); every road on Earth is 10.2 GB (ch 19); a 5,000-hotel chain’s forward inventory is 900 MB (ch 23) | Do not shard. Replicate identical full copies for reads, and spend the interview elsewhere. This fires far more often than candidates believe |
| Is the p99 budget under one cross-continent round trip? | 150 ms, and a page needing two sequential round trips is 300 ms against a 200 ms budget (ch 03) | Regional replicas, a CDN, or precomputation at the edge. Physics, not preference |
| Can two writers touch the same object? | With one owner per object, a compare-and-swap on an 8-byte revision number replaces a 960-byte version vector — 120x smaller (ch 15). With no single owner, you are in ch 06 | Replication stops being a cost question and becomes a correctness question. This is the gate people skip, and it is what makes chapters 06 and 15 different chapters |
4. Worked: the chart applied to a problem with no chapter
The claim in The twenty eight problems and what each one is actually for is that the rules transfer. This section tests that claim on concert ticketing, which the track never covers: Which pattern does this smell like’s fork and its three gates run end to end, so you can see what the procedure produces.
The problem, in one line: 50,000 people want to buy tickets to the same concert, and they all arrive at once.
Start where the framework says to start, with the arithmetic. The input is two lines of product description. The output is the six quantities below, and the last of them turns out to be the design.
assume a 50,000-seat venue, 500,000 buyers arriving in the first 60 s,
each refreshing the seat map every 5 s
seat-map reads/s at peak
500,000 / 5 = 100,000
purchase attempts/s, if every buyer tries once inside that minute
500,000 / 60 = 8,333
read : write
100,000 / 8,333 = 12
successful writes over the entire event, one per seat
50,000
failed purchase attempts, since 500,000 buyers chase 50,000 seats
500,000 - 50,000 = 450,000
failure rate of the purchase call
450,000 / 500,000 = 0.9
Now walk the fork, and then the three gates, in that order.
-
The
read : writeratio is 12:1, which lands in the middle band — above ch 03’s floor of about 10:1 and nowhere near its ceiling of about 100:1. So the chart does not hand you an architecture. It hands you a second question: does a small hot set cover most of the reads?Here it does, absolutely. There is one seat map, and every one of the 500,000 buyers is reading it. One object at 100,000 reads/s is the most concentrated hot set in this book, so the map is served from cache and is stale by design — a seat you clicked may already be gone by the time you click it.
The alternative is 100,000 linearizable reads a second — every read seeing the very latest write — against a table with 50,000 rows. That is an enormous amount of coordination bought to produce an answer that is obsolete a millisecond later anyway.
-
But 12:1 also means the write path is not free. A single threshold would let you declare “the cache is the architecture” and stop; the middle band explicitly does not. At 12:1 you build both paths and say so. That matters here, because the write path is where the actual problem turns out to be.
-
Gate 1, RAM: the working set is 50,000 seats. It fits in one process’s memory a thousand times over, so do not shard and do not spend the interview on partitioning. This is ch 01’s step 0 being right again.
-
Gate 2, latency: buyers for one venue are regional, and the budget is human-scale rather than machine-scale, so the whole thing lives in one region. Put a CDN in front of the static seat-map image, and none at all in front of the write path, which cannot be cached by definition.
-
Gate 3, two writers: absolutely. Two people click seat 14C at the same instant. But there is exactly one owner of that row, so the answer is a compare-and-swap on a seat version number — not a lock, and not a quorum (ch 15).
Ch 23 is the same gate fired in a different domain, and it prices the alternatives. The free fix is to put the check inside the write itself —
UPDATE ... WHERE version = 7— so the condition is evaluated under the lock the write statement already holds, rather than under a second lock you took yourself.
The domain then overrides exactly one branch, and that is the part worth noticing. The chart’s action when two writers collide is “keep both versions”. Here you cannot: a seat is not a document that can be merged. So the losing writer gets an HTTP 409 Conflict and picks another seat.
The last line of the arithmetic is the actual design. Ninety percent of purchase calls must fail. The error path is not an edge case, it is the dominant response of the system — nine out of every ten times the endpoint is called, its job is to say no politely and tell the buyer what to do next.
That reframes the problem away from throughput and onto admission control: a virtual waiting room that lets buyers through at the rate the seat inventory can absorb. It is ch 04’s rate-limiter client contract applied to a product surface.
flowchart LR
U["Buyer"] --> CDN["CDN: seat map<br/>cached, stale by design"]
U --> WR{"Virtual waiting room<br/>admission control"}
WR -->|"admitted at inventory rate"| P["Purchase<br/>compare-and-swap on seat version"]
WR -->|"rate exceeded"| Q["429, wait"]
P -->|"version matched"| OK["Seat booked"]
P -->|"lost the race"| C["409 Conflict, pick another seat"]
One fork gave you a second question, three gates gave you the shape, one number gave you the actual problem, and the domain overrode exactly one branch. That is what the chart is for. It is not a decision procedure, it is a way to stop guessing.
5. The numbers you cannot recompute under pressure
What follows is a recall sheet of forty-odd derived numbers, each paired with the decision it makes. The derivations themselves are slow: every one of these costs a minute or two to rebuild on a whiteboard, and the interviewer stops learning anything new from watching you do so after the second time.
Primitive against derived, because they are memorized differently. A primitive is a hardware constant — how long a memory reference or a disk seek takes. Those live in Latency numbers and what each one forbids, with the full memorization table in Numbers worth memorizing cold. A handful appear below only because a later row depends on them.
Everything else here is derived: a number this track produced by combining primitives with an assumption. Derived numbers are the ones you cannot rebuild in your head inside a forty-five-minute conversation, which is why they are worth carrying.
The only column that matters in an interview is the last: what decision the number makes. A number that decides nothing is not on this sheet.
Volume 1
These are the numbers Volume 1 produces, in chapter order.
| Number | Value | From | What it decides |
|---|---|---|---|
| Seconds per day | 86,400 -> 1e5 | 02 | Every per-day to per-second conversion, at 16% error you state once |
| Memory reference | 100 ns | 02 | In-memory work is free at any web scale |
| SSD random read | 100 us per read; a device does 500 k-1 M IOPS at depth | 02 | 100 sequential random reads is 10 ms of pure I/O. Do not divide 1 by 100 us to get a device ceiling |
| Datacenter round trip | 500 us | 02 | Ten chained internal calls cost 5 ms before any work happens |
| Disk seek | 10 ms, so 100/s per spindle | 02 | Why B-tree depth and LSM compaction are worth arguing about |
| Cross-continent RTT | 150 ms | 02 | You cannot serve Europe from California. This one number forces multi-region |
| Sequential NVMe | ~1 GB/s | 15 | A 4 TB index scan is 1.1 machine-hours, which makes mark-and-sweep GC cheap |
| Cache economics | DB load = QPS x (1-h) | 02 | Each additional nine divides DB load by ten: 90 -> 99% is 10x, not 4x |
mod N resize | 94% of keys move | 05 | The single number that justifies consistent hashing existing |
| Ring resize | 1/(N+1), so 5.9% at N = 16 | 05 | Optimal, and independent of the virtual-node count |
| Virtual nodes | CV ~ 1/sqrt(V), so 7% at V = 200 | 05 | How many virtual nodes, and what they actually buy |
| Quorum | W + R > N | 06 | The only consistency knob in a leaderless store |
| Merkle comparison | O(log n) vs O(n) | 06 | Whether replica repair is a background job or a fantasy |
| Snowflake rate | 4,096/ms/node, so 4.1 M/s/node | 07 | ID generation is never your bottleneck; stop designing it |
2^41 milliseconds | 69.7 years | 07 | Why 41 bits of timestamp, and when your epoch runs out |
| Base-62 code space | 62^7 = 3.52e12 = 96.5 years at 100 M/day | 08 | Seven characters, derived rather than remembered |
| Birthday bound | First collision at 1.177 x sqrt(M) | 08 | “Collisions are rare” is usually off by six orders of magnitude |
| Bloom filter | 9.6 bits/entry at 1% FP | 08 | A 10 M-domain blocklist is 12 MB, so it fits in every process |
| Chunking on insert | fixed blocks 100%, CDC 4% | 8a overwrite is fine insert loses everything for the 100% and the 50,000x, 8b how content defined chunking survives it for the 4% | Offset boundaries versus content boundaries, and 50,000x amplification |
| Coding vs replication | RF 3 = 3x, RS(10,4) = 1.4x | 15 | On a 100 PB corpus that dedups to 75 PB: 225 PB replicated against 105 PB coded, so coding saves 120 PB. Quote the deduplicated figure or the saving does not reproduce |
| Connection tiers | 20 M sockets = 200 GB = 40-200 boxes | 02 | Sized by file descriptors, handshake CPU and blast radius — never by RAM |
Volume 2
These are the numbers Volume 2 produces, again in chapter order.
| Number | Value | From | What it decides |
|---|---|---|---|
| Geohash character | 5 bits, base32; precision 6 is 1,221 x 610 m | 17 | At 500 m radius the disc fits inside a precision-6 cell with probability zero, so the query is nine cells |
k-ring — the k rings of hexagons around a centre cell | 1 + 3k(k+1) cells, k = ceil(r / (1.5a)) | 17 | At r = 1 km: 2.0x overfetch against geohash’s 5.9x, or 68x if geohash stays on character boundaries. Compare the two schemes at the same radius or the comparison means nothing. A k picked by eye misses a crescent 1.5 m wide |
| World road graph | 205 M nodes, 512 M directed edges, 10.2 GB | 19 | Every road on Earth is one box, so distributed shortest path is off the table |
| Dijkstra vs contraction hierarchies — precomputed shortcut edges that let a query skip most of the graph | 30.9 s against 0.5 ms, 61,800x | 19 | Precomputation, not a better heuristic — A* only buys 7.24x and the ellipse bounds it |
| Tile pyramid | 4^z, so the bottom two zoom levels are 15/16 of it | 19 | Where you stop at the bottom is the entire cost of a tile scheme |
| Log against table-as-queue | 8 random page I/Os against one append: 320x | 20 | One NVMe device instead of 328, and a second consumer group for 131 KB |
| Drain time | backlog / (capacity - offered): 150 s at 20% headroom, 600 s at 5% | 20 | Cutting headroom 4x multiplies recovery 4x on identical hardware |
| Active series | 2 KB each; one unbounded label is 2,134x the fleet | 21 | Whether a label is allowed at all. $8,760/year becomes $18.7 M |
| Gorilla encoding — delta-of-delta on timestamps, XOR on values | 16 B down to 1.40 B, 11.4x | 21 | Why samples of one series must be stored adjacently. A general key-value store has no two samples of a series next to each other to compress against, and writes 161x-1,500x more to disk depending on compaction strategy |
| Burn-rate threshold | budget_fraction x 720 / window_hours; 2% over 1 h = 14.4 | 21 | Every row of the alerting table, and a 51.8 s detection time you did not have to choose |
| Watermark | Best single value is 0.30%, at least 3x over budget; 30 s plus amendment is 0.011% | 22 | That a single-horizon pipeline cannot bill, however well you tune it. Quote 0.30% as a floor — “at least 3x over” — not as a tuned optimum |
| Hot partition | 10% of traffic on one key is 7.30x at P = 64; salt 16 gives 1.30x | 22 | Salt only the provably hot keys and the merge stage takes 512 rows/s, which one machine runs |
| Booking transaction | 5 ms gives 200/s on one row; a 3 s gateway call inside it gives 0.33/s | 23 | A 601x collapse. The external call goes outside the transaction, always |
| Per-user inverted index | 774 B per message, 7.7% of that message’s text; 44 MB per mailbox | 24 | An index is affordable. A global one costs 300,000,000x on the read, and that factor is the user count |
| RS(10,4) | 1.4x, tolerates 4; 19.1 nines modelled against 11 advertised | 25 | The gap is correlated failure. Rack diversity alone is worth 16 orders of magnitude |
| Small-object line | k x block = 10 x 4,096 = 40 KB | 25 | Below it, code the extent rather than the object. IOPS, not storage, is the real reason |
| Scatter-gather tail | 1 - 0.99^S: 47% at 64 shards, 99.4% at 512 | 26 | When fan-out stops being an answer, on a query whose per-shard cost is 2% of a core |
| Ledger invariant | SUM(amount_minor) = 0 per currency; 9.6 s on the open partition | 27 | Drift detected in five minutes rather than at the quarterly audit |
| One balance row | 1,333 writes/s, of which 500 us of the 750 us lock hold is the replica ack | 28 | Durability is what serializes, not the hardware. 16 buckets take it to 47% utilization |
| Tick-to-trade | 8.70 + 2.85 = 11.55 us, of which the sequencer is 4.5 (39%) | 29 | Which microsecond to attack, and that the biggest one is a durability decision |
| Kernel network stack | 13.2 us round trip = 114% of that budget | 29 | Bypass is bought for the jitter, not the mean — and it costs one spinning core |
The point of these tables is not recall, it is speed. Every one of these is a number you would otherwise spend ninety seconds deriving in a forty-five minute conversation, and the derivation adds nothing the interviewer wants once you have shown you can do it twice.
6. Seven failure shapes, which is all of them
Twenty-seven of the twenty-nine chapters carry a failure-modes table — every one except ch 02, which is an estimation drill, and this one — and across all of them the same seven shapes recur.
Learning the shape is worth more than memorizing the instances, because the shape tells you what to alert on. An instrument you did not decide to build is an instrument you do not have during the incident.
The instances are there so you can see the shape repeat across unrelated domains — skim them, do not memorize them. The tell is the observable signal that says this failure is happening right now, and the guard is what prevents it. In an interview you spend the tell and the guard; the instances are only evidence that the shape is real.
| Shape | Instances | The tell | The guard |
|---|---|---|---|
| Step function on dependency loss | Cache tier dies and the database goes 26x in one second (08); one lagging consumer evicts the page cache and every other consumer’s reads become disk reads (20) | Load on the dependency, not on the thing that failed | Provision the dependency for a survivable multiple; in-process LRU; coalesce misses per key |
| Storm | Retry storm (04), reconnect storm and cursor stampede (15), rebalance storm (20), a 20x replay burst after a ten-minute partition (21), 500 subscribers detecting one dropped packet at once (29) | A spike in request or connection rate with no matching spike in work | Exponential backoff with full jitter, a client-side cap, and a server-side admission limit. Never a queue whose wait can exceed the sender’s timeout |
| Silent data loss | Last-write-wins and a dropped reference count (15), a pruned version vector (06), unclean leader election truncating 234,240 records with offsets going backwards (20), a Bloom false positive discarding a real billable click (22) | Nothing. There is no error, which is what makes it the worst class | An invariant you can check offline, and a resolution rule that never discards |
| Hot key | Viral link (08), celebrity fan-out (11), a chunk in two million accounts (15), a 10% advertiser at 7.30x (22), the top-10 board (26), one merchant’s balance row (28) | Requests per second per key, which most dashboards do not show | Local LRU or a TTL cache for hot reads; salting or sub-balance buckets for hot writes. Partitioning cannot help either one |
| Clock | Snowflake rewind (07), timestamp-ordered conflict resolution (15), out-of-order samples rejected by an append-only chunk encoder (21), game-server skew reordering equal scores (26) | Duplicate IDs, or an ordering that disagrees with causality | Monotonic clocks locally; timestamp at the one service that owns the order; never order across machines by wall clock |
| Unbounded growth | Change journal and orphaned chunks (15), the raw click log (08), noncurrent object versions at $560,000/month with no lifecycle rule (25), pending holds a stopped sweeper never releases (23) | A side table growing faster than the thing it describes | A retention policy and a GC pass, both decided at design time rather than during the incident |
| Drift between two computations of the same quantity | Streaming aggregate against the batch recount (22), the ledger against the payment provider’s settlement file (27), a stored balance column against the sum of the entries it should equal (28), a hot standby’s output hash against the primary’s (29) | Nothing at all, until something compares them on purpose | An independent recount on a schedule, a threshold aged — required to hold for a while before it pages — and a stated rule for which side wins |
Three of these seven are invisible without an instrument you had to decide to build — silent data loss, hot keys, and drift — and those are the three an interviewer is most impressed to hear you name unprompted. All three share the same tell, which is that nothing is on fire: no error rate moves, no latency graph bends, and the only way to see them is a check you wrote before you needed it.
7. What this track does not cover
Eight subjects this track uses without teaching, where each gap will bite you, and what to read instead.
Being honest about the boundary is more useful than pretending there is not one. It is also the answer to the wrap-up question about what you are least sure of — an answer you can give in one sentence because you decided it in advance rather than on the spot.
| Not covered | Where the gap bites | Where to go |
|---|---|---|
| Consensus internals | Chapters 05, 06 and 20 use leader election and cluster membership as a black box; 29 prices a majority acknowledgement at 4.5 us without deriving the protocol that produces it | The Raft paper, described in Seven papers and the problem each one actually solved. Then implement leader election once; it is a weekend |
| Cross-shard serializable transactions | 23 and 28 both price two-phase commit and both choose a saga instead. Nothing here builds a system that actually offers the guarantee | Spanner and Percolator, both Google systems that do offer it — Spanner a globally distributed database, Percolator an incremental-processing layer built over BigTable. Spanner is also Seven papers and the problem each one actually solved’s honest counterweight: the guarantee is purchasable and the invoice is in latency |
| Stream joins, and the engine underneath | 22 derives windowing, watermarks, exactly-once processing and restatement, but never joins two streams together, and it names checkpoint-barrier alignment — the way a stream engine takes a consistent snapshot mid-flight — as a cost without deriving it | The Dataflow model paper — Google’s formalization of windowing and watermarks — for the semantics ch 22 does not reach; then the checkpointing design of Flink, the open-source stream engine that implements it |
| Query planning and storage engines | Assumed throughout | sql/03 covers B-trees, log-structured merge trees, query plans and multi-version concurrency control properly |
| Authorization models and key hierarchies | Tenant isolation is covered — per-tenant limits and selective shedding in 21, isolation-by-partition in 24. What is missing is authorization modelling — deciding who may do what — plus key rotation and encryption key hierarchies; 15 and 24 price the side channel that convergent encryption opens and stop there — convergent meaning the encryption key is derived from the content itself, so identical files encrypt identically and can therefore be deduplicated, which is exactly what lets an attacker test whether a file is already stored | Any serious treatment of capability-based authorization; your employer’s threat model |
| Tracing, and logs as a designed system | 21 covers metrics, service level objectives and alerting end to end. Distributed tracing — spans, context propagation, tail sampling — appears nowhere, and logs are only ever priced (01), never designed | The SRE workbook’s SLO chapters alongside ch 21; then instrument something and watch it lie to you |
| Cost as an org function | Priced per design — dollars per petabyte-month in 25, dollars per box-year in 21, dollars per day of miscounting in 22 — never as a budget owned by a team | The GenAI and agents tracks price model inference explicitly |
| ML and generative systems | A different interview with a different scoring rubric | The other tracks in this repo |
8. Seven papers, and the problem each one actually solved
Seven foundational systems papers, each summarized to the level you would need to discuss it in an interview: what problem it solved, and what that solution costs.
Read the originals for the problem statement, not the implementation. Every one of them is a case of “we could not buy this, so we had to invent it,” and knowing what could not be bought is what makes the design legible. Each entry below is written in the same three moves — the problem, the mechanism, the price — because that is the shape of the answer an interviewer wants when they ask what a paper is about.
Dynamo (Amazon, 2007)
The problem. A shopping cart must accept a write during a network partition. A rejected “add to cart” is lost revenue, and a rejected checkout is worse.
The mechanism. Everything follows from refusing to ever say no to a write. Consistent hashing places data without asking a coordinator. Version vectors exist because concurrent conflicting writes are now normal rather than exceptional. Sloppy quorums and hinted handoff — accepting a write on whatever replicas can be reached, and having them hand it to the rightful owner once the network heals — mean a partition does not stop writes. Merkle trees then find and repair the divergence afterwards.
The price, and the part worth internalizing: Dynamo pushes reconciliation to the application. That is why the cart resurrects deleted items. The merge rule for a cart is “union,” and union has no delete.
Chapters 05 and 06 are this paper with the arithmetic filled in.
BigTable (Google, 2006)
The problem. Petabytes of structured data whose schema varied per row, at a write rate that made B-trees untenable.
The mechanism. A sparse, sorted, distributed map keyed by (row, column, timestamp). It is stored as immutable files called SSTables, with an in-memory buffer called a memtable in front of them absorbing writes, and a background compaction process behind them merging the files back together.
That arrangement — buffer in memory, write out whole sorted files, merge later, never update in place — is the log-structured merge tree, or LSM. It is why sequential writes beat random ones by three orders of magnitude (sql/03), and that same gap is the whole of ch 20’s 320x.
The price, and the consequence that decides designs: the row key is the only index, so the schema is the access pattern. You cannot add a query later without rewriting the data. Everything modern that calls itself a wide-column store is a descendant.
GFS (Google, 2003), and Colossus after it
The problem. Storing files larger than any single disk, on hardware that fails constantly, for a workload that appends far more than it overwrites.
The mechanism, and the design decision worth stealing: one master holding all metadata in memory, and dumb chunkservers holding all the bytes. That is exactly the metadata-versus-blob division chapters 15, 24 and 25 keep returning to.
The single master looks like a scandal until you notice two things: metadata is about a thousandth of the data, and the client talks to the master once per file, not once per byte.
Colossus is the sequel. It removed the single master and moved from whole copies to Reed-Solomon erasure coding; ch 25 is that arithmetic derived, including the parts the marketing skips.
MapReduce (Google, 2004)
The problem, stated correctly. The commonly told story is that MapReduce made parallelism easy. It did not — parallelism was already easy. It made fault tolerance easy, and that is the actual contribution.
The mechanism. If every task is deterministic and free of side effects, a task on a dead machine can simply be re-run somewhere else. Nothing needs to be undone, and no other task needs to know. A 1,000-machine job stops being a coordination nightmare and becomes bookkeeping.
That is the same determinism ch 29 buys at the opposite end of the timescale, and the same reason ch 22 can treat replay as routine. Spark and Flink changed the execution model and kept the insight exactly.
Kafka (LinkedIn, 2011)
The problem. Many consumers reading the same event stream at different speeds. A traditional queue cannot do this, because the broker tracks per-message delivery state for every consumer.
The mechanism: make the log the primary object and push the offset — the read position — out to the consumer. The broker then does sequential disk writes and nothing else. Replaying old messages is free, because nothing on the server had to be undone.
That is the same structural idea as the per-user cursor in ch 15: the reader owns its position, so the server holds no per-reader state, and both resume and replay come for free.
Ch 20 is this paper with every constant priced.
Raft (Ongaro and Ousterhout, 2014)
What consensus is, first. Consensus is the problem of getting a group of machines to agree on a single ordered sequence of decisions even while some of them fail. It is what “elect a leader” and “replicate this log” actually rest on.
The problem Raft addressed was not correctness. Paxos, the earlier protocol, was already correct. The problem was that almost nobody could implement Paxos without getting it wrong.
The mechanism is decomposition: leader election, log replication, and safety presented as three separable mechanisms, plus a membership-change protocol that Paxos papers left as an exercise.
The price. Read this paper before you say “we use consensus” in an interview, because the follow-up is what happens during an election. The answer is that writes stop for an election timeout — typically 150-300 ms. That is a real number, and you should be prepared to defend it against your latency budget.
Spanner (Google, 2012)
The problem. External consistency across datacenters: if transaction B commits after transaction A finished, then every observer anywhere must see B ordered after A. Not eventually — immediately and globally.
The mechanism is TrueTime, which stops pretending a clock reading is a point and treats it as an interval. Bound the clock uncertainty using GPS receivers and atomic clocks, then have each commit wait out that interval before releasing its locks. Waiting guarantees that the next transaction’s timestamp really is later.
The price, and the honest lesson: every commit waits roughly the clock uncertainty. Global strong consistency costs milliseconds per write, permanently, by design.
That is the counterweight to the entire eventual-consistency argument in chapter 06, and to the gap What this track does not cover admits this track never fills. Strong consistency across regions is purchasable, and the invoice is denominated in latency.
9. The other tracks in this repo
Four different design rounds share a shape and are scored on completely different things, so it matters which one you are actually in — reading the wrong framework an hour before the interview is a recoverable mistake only if you notice. Five things are listed below and only four of them are rounds: the fifth, database internals, is the substrate all four stand on and nobody interviews you on it under that name.
- ML system design — machine learning, meaning a system whose behaviour is learned from data rather than written down. It is the same skeleton as this track plus three extra stages that dominate the score: framing the learning objective, data and labels, and the gap between the metric you measured offline and the one that moved in production. The distinguishing failure is treating the model as the system — the interview is mostly about labels, features, and why the offline number improved while the online one did not. Ch 19’s ETA is this track handing a problem across that boundary and saying so out loud.
- GenAI system design — generative AI, where a model produces free-form text or images and there is therefore no single correct output, which makes evaluation the system rather than a stage of it. Cost scales with how much the model writes and superlinearly with how much context you give it, and generation is sequential — one token at a time — so the latency budget decomposes differently from anything in this track.
- Agent design — an agent being a model that calls tools in a loop to accomplish a task. This is a seven-step method for that round: clarify, tier, loop, tools, context, failure modes, then evaluations and cost. It is the closest in spirit to this track, and the phrases that signal seniority list transfers verbatim.
- Object-oriented design — a separate round with a separate rubric: clarifying questions, actors, a class diagram, the two or three decisions that imply a design pattern, then working code. Fourteen chapters cover it: what the round is, the framework, object-oriented programming fundamentals, and eleven worked problems from a parking lot to a restaurant. Do not walk into it with this chapter’s habits — nothing there is decided by an estimate.
- Database internals — the layer underneath everything here, and not a round of its own. If you cannot say why the query planner declined to use an index, or what a page is, then the storage answers in this track are recited rather than understood. Ch 23 is the chapter that spends it most directly: its whole deep dive is an argument about transaction isolation levels.
The framework chapters are interchangeable in structure and not in content. Read the framework for the round you are actually in, an hour before you are in it.
10. How to practice, in the order that works
Five practice steps, arranged so that each depends on the one before it. Doing them out of order mostly wastes the later ones.
- Redo chapter 02’s six estimations on a timer, out loud, without notes, three minutes each. If the arithmetic is not automatic, nothing else in this track will surface under pressure, because every other skill here is downstream of a number you produced quickly.
- Take one chapter and rebuild it from the requirements, without reading it. Chapter 08 is the right one to start with because the whole design turns on two numbers; chapter 15 is the right one to finish Volume 1 with because it turns on six. From Volume 2, rebuild chapter 23 — it is the one where the arithmetic’s entire job is to buy you permission to spend forty minutes on a race condition, which is a different skill from sizing a fleet.
- Do a problem this track does not contain — a ticketing system, a ride-hailing dispatcher, a collaborative text editor — and use Which pattern does this smell like’s fork and its three gates to pick your two deep dives, exactly the way Worked the chart applied to a problem with no chapter does. Then check yourself against ch 03’s rubric. For each one, write down where the decisive constraint came from, and whether the chart got you there or the domain overrode a branch — that is the same move Worked the chart applied to a problem with no chapter makes at its last step.
- Practice the wrap. Five minutes of “here is what I would build first, here is what I would measure, here is what I am least sure about” is worth more than a fourth deep dive, and it is the part almost nobody rehearses (ch 03). The last of those three clauses is what The assumption ledger is for.
- Read one paper from Seven papers and the problem each one actually solved a week. Not to implement it, but to be able to say what problem it solved in two sentences.
11. The assumption ledger
Every design is a set of assumptions with a diagram attached, and the diagram is only correct relative to them. This chapter is no exception: its advice, its decision chart and its worked example all rest on things that could be otherwise. They are collected here, so that you can state the foundations in twenty seconds and say what replaces the advice when each one fails.
Sort each assumption into one of three bins:
- State it. You are free to pick, and being wrong costs a re-derivation and nothing more.
- Ask it. The answer moves a policy or a threshold, so it is worth an interviewer’s time.
- Load-bearing. If this is wrong the design is not suboptimal, it is invalid — a box appears or disappears, rather than the count inside a box changing.
The one-line test for which bin something goes in, from ch 03: move the assumption an order of magnitude in each direction and ask whether the set of boxes changes, or only the number of machines inside them.
The table below applies that test to the thirteen assumptions this chapter rests on; the last column — what you would build instead — is the one that turns an admission into an answer.
| Assumption | Bin | What it holds up | What replaces it if it is false |
|---|---|---|---|
| The mechanisms recombine — an unseen problem is a new arrangement of known parts | Load-bearing | The existence of this chapter. Both rule tables (Volume 1 as twenty one rules, 1b volume 2 as twenty five more), the claim in The twenty eight problems and what each one is actually for that chapters 09-14 introduce no new mechanism, and the whole of Worked the chart applied to a problem with no chapter | If each problem were genuinely novel, a rule table is a liability rather than an aid, and the right preparation is deriving from primitives every time instead of recognizing shapes |
| The round is roughly forty-five minutes of open conversation, scored on reasoning rather than on a correct answer | Load-bearing | Why The numbers you cannot recompute under pressure is a recall sheet instead of a derivation, why How to practice in the order that works rehearses the wrap, and why Which pattern does this smell like optimizes for speed of dispatch | For a multi-hour take-home or a written exercise, none of the compression helps — you would want the full derivations, and time pressure stops being the constraint the chapter is built around |
| Exactly one of the five opening questions dispatches | Load-bearing | The shape of Which pattern does this smell like’s chart: one branch node and three flat gates, rather than a tree several levels deep | If two questions dispatched independently the correct picture is a grid rather than a tree, and the reader would need to evaluate combinations instead of walking one path |
| The three gates fire independently of which fork you took | Load-bearing | Presenting them as a checklist run every time, rather than as further levels of the chart | If a gate only applied inside certain leaves it belongs inside the tree, and the flat checklist would hide a dependency the reader has to know about |
| In Worked the chart applied to a problem with no chapter, demand exceeds supply by an order of magnitude — 500,000 buyers chasing 50,000 seats | Load-bearing | The 90% failure rate, and therefore the entire reframing from throughput onto admission control and a virtual waiting room | If supply met demand the failure path is a genuine edge case, the waiting room disappears, and the answer is an ordinary transactional booking system |
| In Worked the chart applied to a problem with no chapter, all buyers arrive inside 60 seconds | Load-bearing | The 8,333 purchase attempts a second, and therefore the 12:1 ratio that puts the problem in the middle band at all | Holding the read rate fixed, spreading the same buyers over an hour gives 500,000 / 3,600 = 138.9 writes/s and 100,000 / 138.9 = 720 reads per write. That is past the 100:1 ceiling, so the problem leaves the middle band entirely and becomes an ordinary read-heavy caching design |
| The ~10:1 and ~100:1 fork thresholds | Ask it | Which of the three branches a borderline problem takes, including Worked the chart applied to a problem with no chapter’s at 12:1 | Moving a threshold reclassifies borderline problems, but the middle band’s instruction — build both paths and let the access distribution break the tie — is what a borderline problem gets under any threshold. The instruction is the durable part, not the boundary |
| The 5-second seat-map refresh in Worked the chart applied to a problem with no chapter | Ask it | The 100,000 reads/s, and so the other half of the ratio | It is a client-side product decision, which makes it the cheapest thing in the whole design to change and therefore exactly what an interviewer should probe. Halving the refresh rate halves the read tier |
| A 128 GB commodity machine as the default in gate 1 | Ask it | Where the “does it fit in one machine” line sits, and therefore how often that gate declines to shard | Bigger machines exist and move the line up by roughly an order of magnitude. The gate’s finding — that it fires far more often than candidates believe — gets stronger, not weaker |
| The 50,000-seat venue in Worked the chart applied to a problem with no chapter | State it — explicitly not load-bearing for the fork | The 450,000 failed attempts, the 90% failure rate, and gate 1’s verdict that the working set is trivially small | It cannot change which branch you take. See the paragraph below |
| Which chapter derived a given rule | State it — explicitly not load-bearing | Only the second column of both rule tables, which is navigation | A rule’s truth does not depend on where it was derived. If a mechanism had been introduced in a different problem, every one-line rule in Volume 1 as twenty one rules and 1b volume 2 as twenty five more reads identically |
| The 150 ms cross-continent round trip in gate 2 | State it | The verdict that a page needing two sequential round trips cannot meet a 200 ms budget | It is close to a physical constant — the speed of light in fibre over intercontinental distance — so it does not move much. If it did, the gate would fire on a different set of designs and nothing about how you check it would change |
| The exact counts: 28 problems across 29 chapters, 46 rules, 7 failure shapes, 7 papers | State it | Only the section headings | These are inventory. A track with 35 chapters would produce a longer table and the same reading procedure |
Why the venue size cannot move the answer
The 50,000-seat venue is the number to mark as explicitly unable to change the answer. It looks decisive: it appears in three of the six lines of Worked the chart applied to a problem with no chapter’s arithmetic, and it produces the memorable 90% failure rate.
It still cannot move the fork, and the reason is structural rather than numerical. The seat count appears in neither rate. Write the two rates out symbolically, with B for the buyer population:
reads/s B / refresh interval = B / 5
writes/s B / arrival window = B / 60
read : write (B / 5) / (B / 60) = 60 / 5 = 12
B cancels, and the seat count was never in the expression at all. The ratio is a function of the two time intervals and nothing else.
That is a stronger statement than it first looks. You can concede the venue size, and you can concede the crowd size too. The only two numbers that can move this problem out of the middle band are the refresh interval and the arrival window.
Test it: shrink the venue to 5,000 seats. The failure rate rises to 495,000 / 500,000 = 0.99, the read:write ratio stays at exactly 12:1, and every architectural conclusion holds.
What the seat count does decide is how loudly the error path dominates, and whether the inventory fits in memory. Fifty thousand rows clears the memory bar by a factor of thousands, and so would five thousand or five hundred thousand.
So concede the venue size instantly and spend the challenge on the arrival window, which is the one input that genuinely moves the design.
The sentence that makes this visible to an interviewer: “This whole approach rests on four things. One, that unfamiliar problems are recombinations of known mechanisms, which is what makes a rule table worth carrying. Two, that I have forty-five minutes and am being scored on reasoning, which is why I recall numbers instead of deriving them twice. Three, that the read:write ratio is the one question that dispatches, which is why my first move is always to compute it. Four, on this specific problem, that all the demand lands inside a minute — that is what makes it a write-path problem, and if it were spread over an hour I would be designing something else. The size of the venue is not one of them.”
Cheat sheet
This is the whole chapter compressed to twenty lines. If you read nothing else the morning of the interview, read this and Which pattern does this smell like.
| The one-line thesis | Twenty-eight problems, forty-six rules. The problems were the delivery vehicle |
| The two volumes | Vol 1 teaches the mechanism; Vol 2 teaches which constraint is binding and what the honest version costs |
| Before any design | Five questions (ch 03): read:write · consistency per field · p99 and where the users are · retention · growth |
| The one fork | Under ~10:1 the write path is the system; over ~100:1 caching is the design; between them, build both and let the access distribution break the tie |
| If write-heavy | Newer value: one slot, overwritten. New fact: a log, then windowed aggregation with absolute-value upserts |
| If read-heavy | DB load goes as (1-h), each extra nine divides it by ten — then ask whether one key carries the reads |
| The three gates | Does the working set fit in RAM · is the budget under one 150 ms RTT · can two writers touch one object |
| Before sharding | Ask whether the working set fits in RAM. Every business on Earth is 60 GB; every road is 10.2 GB |
| When sharding | Hash ring, key = the one reads use, 1/(N+1) moves instead of 94%. And salt the provably hot key |
| When replicating | W + R > N, and say which side of CAP you took during a partition |
| When two writers collide | One owner: compare-and-swap. No owner: version vectors. Never last-write-wins |
| On any retry path | Idempotency key, exponential backoff, full jitter. Content addressing gives you the key free |
| Across a boundary you own | Saga with compensations, not 2PC. A dead coordinator holds locks nobody may release |
| Across a boundary you do not | Commit the key before the call; on a timeout, ask — never re-send |
| On any money | Double-entry, integer minor units, and reconcile against an independent computation |
| On any storage bill | RF 3 vs RS(10,4) is 3x vs 1.4x, and coding is paid for in tail latency and small objects |
| On any rate you derive | Say whether it is offered load or service capacity, and never divide one by the other |
| The estimate’s real output | The name of the binding constraint, not a number |
| The wrap | What you would build first, what you would measure, what you are least sure about |
| What to read next | Dynamo, then GFS, then Raft. In that order |
Where to go from here: 03 — Interview Framework is how the forty-five minutes is spent, minute by minute; 02 — Back-Of-The-Envelope is the estimation drill you repeat until it is automatic; 17 — Proximity Service opens Volume 2 and is the next chapter in the study plan; and ML and GenAI are the same conversation scored against a different rubric.