Edition 1·Updated 2026-08-19·28 min read
Sources
About this book
An overview of the book, with source information for further reading.
Designing Data-Intensive Applications
Martin KleppmannBehind the dizzying array of buzzwords—NoSQL, Big Data, eventual consistency, CAP theorem, MapReduce, stream processing—lie a small set of enduring principles that govern how data systems behave.
Martin Kleppmann's Designing Data-Intensive Applications strips away the marketing to give software engineers and architects a technically precise understanding of how databases store and retrieve data, how replication and partitioning work, what guarantees transactions and consensus can and cannot provide, and how batch and stream processing fit together. Rather than tutoring you on one tool, it teaches you to reason about the fundamental trade-offs—reliability vs. cost, consistency vs. availability, timeliness vs. integrity—so you can choose, combine, and operate the right tools for any data-intensive application and design systems that survive the messy realities of hardware faults, network failures, and human error.
Movement I
Orient
What this book claims, and who wrote it.
- — The book's one-line promise
- — The author and where the book stands
A deep, principles-first guide to the architecture of reliable, scalable, and maintainable data systems, explaining the trade-offs behind databases, distributed systems, and data processing.
The need-to-know
Reliability, scalability, and maintainability are the three foundational concerns that should guide all data system design. There is no single right solution for storing and processing data—every approach has trade-offs appropriate to different circumstances. Distributed systems face partial failures, unreliable networks, unreliable clocks, and process pauses that make reasoning fundamentally harder than single-machine systems.
About this guide
The guide describes these challenges, steps and possible outcomes.
Who it is for
You are building a real capability: Designing Data-Intensive Applications.
Challenges
- In practice · Reliability erodes when it is left to instinct instead of method.
- For the reader · You were taught the moves piecemeal, never the whole model.
Steps to consider
- 1Master data model and encoding choice.
- 2Master storage engine design.
- 3Master replication strategy.
Risks
You stay dependent on instinct, and it fails you when the stakes are highest.
Intended result
Reliability becomes something you produce by design, not by luck.
Set the record straight
What this book sets straight
The common beliefs this book pushes back on.
Transactions are the antithesis of scalability and must be abandoned in large-scale systems.
Transactions have real costs and benefits like any design choice; many applications need their guarantees, and there are nuanced ways to achieve correctness without full distributed transactions.
Eventual consistency is inevitable in scalable systems, so just learn to deal with it.
Stronger guarantees like causal consistency are achievable without sacrificing much performance, and log-based derived data offers strong integrity without distributed transactions.
A single general-purpose database can satisfy all of an application's data needs.
No single tool fits all access patterns; real applications compose specialized storage, indexing, and processing systems, keeping them in sync through dataflow.
The CAP theorem (pick 2 of 3: Consistency, Availability, Partition tolerance) is a useful design guide.
CAP is narrowly defined, often misunderstood, and of limited practical value; partitions are faults you don't choose, so the real choice is being consistent or available when partitioned.
Just because a database provides strong safety properties like serializable transactions, applications are guaranteed correct.
End-to-end correctness requires application-level measures like idempotent operations and duplicate suppression; low-level guarantees are not sufficient by themselves.
Movement II
Map
The book's main ideas and how they connect.
Designing Data-Intensive Applications's own model — and how it sits inside its field.
- — 13 constructs the book works with
- — Where it agrees with the field, exceeds it, or fills a gap
The constructs
How they connect (16)
- Data Model and Encoding Choice → influences → System Complexity
- Data Model and Encoding Choice → influences → Maintainability
- Storage Engine Design → influences → Scalability
- Replication Strategy → influences → Reliability
- Replication Strategy → predicts → Consensus and Ordering Mechanism
- Partitioning Strategy → influences → Scalability
- Transaction and Isolation Guarantee Level → influences → Reliability
- Transaction and Isolation Guarantee Level → influences → Scalability
- Distributed Environment Unreliability → moderates → Consensus and Ordering Mechanism
- Distributed Environment Unreliability → influences → Reliability
- Workload Load → moderates → Scalability
- Consensus and Ordering Mechanism → mediates → Reliability
- Dataflow Integration Approach → mediates → Maintainability
- Dataflow Integration Approach → influences → Reliability
- System Complexity → influences → Maintainability
- System Complexity → influences → Reliability
Where this book diverges from the corpus
- exceeds The field folds schema/encoding into a broad architecture construct, whereas the book dissects data models, serialization formats, and schema evolution in far greater depth.
- exceeds The book treats LSM-trees, B-trees, and column stores as first-class engineering topics the field only mentions in passing under storage.
- exceeds The book gives detailed leader/leaderless and sync/async replication tradeoffs that the field's architecture construct only names, not the misleading governance pre-match.
- exceeds The book rigorously covers key-range/hash partitioning and rebalancing while the field only lists partitioning as one word in its architecture construct.
- fills gap No corpus construct addresses transactional isolation levels, serializability, or atomic commit, making this a genuine contribution.
- fills gap The field has no construct for partial failures, clock drift, and process pauses as a modeling condition.
Movement III
Master
Explore the book's ideas, examples and practical tools.
How the author makes the case — section by section, with the book's own tools.
- — 13 sections, in the book's order
- — The book's frameworks, checklists, and worked cases
strong · 1 source
- Designing Data-Intensive Applications
This section names the physical realities you cannot design away: dropped packets, unbounded delays, clock drift, and process pauses that produce partial, undetectable failures. You will learn to build systems that assume these rather than hope against them.
Distributed Environment Unreliability
The contextual condition that networks drop or delay packets, clocks drift and are unsynchronized, and processes pause unpredictably, producing partial failures that are nondeterministic and hard to detect.
Why it matters. Treating the network and clocks as reliable produces systems that appear correct in testing and fail catastrophically and nondeterministically in production during the exact partial failures you failed to model.
Myth
Engineers believe a timeout reliably tells them whether a remote node has failed.
Reality
A timeout only tells you that you received no response in time — the node may be alive, slow, GC-paused, or the response may be in flight. You can never distinguish a crashed node from a slow one, which is why fencing and quorums exist.
- You cannot detect failure directly — you can only observe the absence of a response, which is ambiguous.
- Clock timestamps are unsafe for cross-node ordering; drift and skew are measured in tens of milliseconds or worse.
- Fencing tokens are the defense against a paused node waking up and acting on stale authority.
The deep drill-down: 7 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Partial-Failure Interaction Audit” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section teaches you to characterize load with the right parameters — read/write ratio, data volume, concurrency, fan-out — before you make any scaling decision. You will learn that 'load' is a vector, not a single number.
Workload Load
The volume and pattern of data and requests placed on the system, including read/write ratio, data volume, concurrency, and access patterns that stress its capacity.
Why it matters. Describing load with the wrong parameter (requests per second when the real driver is fan-out or tail latency) leads you to scale the wrong dimension and leaves the actual bottleneck untouched.
Myth
Practitioners summarize load as average throughput or average response time.
Reality
Averages hide the failures your users actually experience; tail latency (p99, p999) governs perceived reliability, and a few slow requests from the heaviest users define your capacity. The load parameter that matters is often a distribution, not a mean.
- Reliability-Scalability-Maintainability (RSM) Analysis FrameworkFramework — A mental model for evaluating and reasoning about the design of a data-intensive application.
- Partition Rebalancing (Adding a Node)Process — To move some partitions from existing nodes to the new node to distribute load evenly.
- Load is a set of parameters; name the one that actually drives cost before scaling.
- Tail-latency percentiles, not averages, describe the experience your users have.
- The dominant load parameter can be a derived cost like fan-out rather than raw request count.
The deep drill-down: 8 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Load Parameter Sheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for · 2 tools for this section. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section explains linearizability, total order broadcast, and consensus algorithms — the machinery that lets independent nodes agree on facts and event order despite faults. You will learn where you genuinely need consensus and where you can avoid its cost.
Consensus and Ordering Mechanism
The use of mechanisms for getting nodes to agree and for ordering events, including linearizability, total order broadcast, and consensus algorithms that enable correct coordination despite faults.
Why it matters. Reaching for consensus where you don't need it saps performance and availability, while skipping it where you do produces split-brain and duplicated leaders that silently violate uniqueness constraints.
Myth
Engineers think they must implement consensus themselves or that any coordination problem requires a full consensus protocol.
Reality
Consensus is equivalent to problems like uniqueness constraints, atomic commit, and leader election, and it is almost always better delegated to a proven coordination service (like ZooKeeper/etcd) than hand-rolled. Many problems that look like they need consensus can be reframed to avoid it entirely.
- Leader election, atomic commit, and uniqueness constraints are all consensus in disguise — solve them with one proven mechanism.
- Total order broadcast and consensus are equivalent; a replicated log is the practical form.
- Linearizability costs availability under partition, so apply it surgically, not globally.
The deep drill-down: 8 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Ordering & Consensus Selection Sheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section covers how to keep heterogeneous systems (databases, caches, search indexes, warehouses) in sync using batch jobs, stream processing, change data capture, and event logs. You will learn to treat derived data as a reproducible function of a source of truth.
Dataflow Integration Approach
The way heterogeneous data systems are kept in sync through derived data, using batch processing, stream processing, change data capture, and event logs to flow changes between systems.
Why it matters. Without a disciplined dataflow, engineers wire systems together with ad-hoc dual writes that drift out of sync, producing the bugs where the search index and the database disagree that no one can debug.
Myth
Practitioners solve integration by having the application write to every system directly (dual writes).
Reality
Dual writes have no atomicity across systems and race under concurrency, so they inevitably diverge; capturing changes from a single source of truth (via CDC or an event log) and deriving everything else eliminates the race by construction.
- Unbundling the DatabaseFramework — A design philosophy for building data systems by composing specialized, loosely coupled components (event logs, stream processors, storage systems) rather than using a single monolithic database.
- Event SourcingFramework — An application design pattern where all changes to application state are modeled and stored as a sequence of immutable events.
- Derived data flowing from a single log is reproducible and self-healing; dual writes are not.
- Change data capture converts the database's own log into the integration backbone.
- Idempotent, replayable derivations let you rebuild any downstream system without special-case recovery code.
The deep drill-down: 7 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Dataflow Link Specification” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for · 2 tools for this section. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section distinguishes inherent complexity (from the problem) from accidental complexity (from the solution) and gives you levers — good abstractions, loose coupling — to contain the latter. You will learn to spot complexity accumulating before it ossifies.
System Complexity
The degree of accidental and inherent complexity in the system, manifested as tight coupling, tangled dependencies, and difficulty for engineers to understand and reason about behavior.
Why it matters. Accidental complexity compounds silently until the system becomes a big ball of mud where every change risks breaking something unrelated and engineers fear touching the code.
Myth
Engineers believe complexity is an unavoidable price of a system doing important work.
Reality
Much complexity is accidental — arising from leaky abstractions, tight coupling, and special cases — and is removable without reducing functionality. The goal is not simplicity of behavior but simplicity of the mental model needed to reason about it.
- Accidental complexity is removable; inherent complexity is not — knowing which is which directs your effort.
- The measure of simplicity is the size of the mental model needed to reason about the system.
- Good abstractions reduce complexity; leaky ones just relocate it.
The deep drill-down: 7 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Complexity Coupling Audit” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section frames reliability as continuing to work correctly under hardware faults, software bugs, and human error, and shows how to engineer for fault tolerance rather than fault avoidance. You will learn to treat faults as expected inputs, not exceptions.
Reliability
The system continuing to work correctly, performing the desired function at the desired performance level, even in the face of hardware faults, software errors, and human mistakes.
Why it matters. A system designed to avoid faults rather than tolerate them fails hard and rarely, which means when it does fail no one is prepared and recovery is improvised.
Myth
Practitioners equate reliability with buying more reliable hardware to prevent failures.
Reality
Hardware faults are inevitable at scale, and the biggest source of outages is human error, not hardware; reliability comes from tolerating faults through redundancy, testing, and blast-radius limits, not from preventing them. A fault is a component deviating; a failure is the whole system stopping — the job is to keep the former from becoming the latter.
- Reliability is fault tolerance, not fault avoidance — assume components will fail and contain the damage.
- Human error, not hardware, causes most outages; design the system to make mistakes recoverable.
- Deliberately inducing faults is the only way to know your recovery paths work.
The deep drill-down: 7 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Fault-to-Failure Containment Worksheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section defines scalability as coping with increased load by reasonable means of adding resources, and connects it to your storage engine, partitioning, and isolation choices. You will learn to ask 'scale along which dimension?' rather than treat scalability as a binary property.
Scalability
The system's ability to cope with increased load in data volume, traffic, or complexity through reasonable means of adding computing resources while maintaining good performance.
Why it matters. Optimizing for a scalability dimension you don't actually face wastes engineering effort and often adds complexity that hurts you on the dimension that does grow.
Myth
Engineers treat scalability as a fixed attribute a system either has or lacks, and reach for distributed architecture prematurely.
Reality
Scalability is relative to a specific load parameter and growth path — a system that scales writes may not scale complex joins. Many systems that fear scaling would run fine on one big machine, and premature distribution imports coordination costs that reduce effective throughput.
- Scalability is always along a named dimension; 'is it scalable?' is an ill-formed question.
- A single powerful machine outscales a poorly-coordinated cluster for many real workloads.
- Strong isolation and consensus buy correctness at a throughput cost — apply them selectively to preserve scale.
The deep drill-down: 6 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Scalability Growth-Scenario Worksheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section gives you a working definition of maintainability as three concrete sub-properties — operability, simplicity, and evolvability — and shows how each is designed in rather than added later. You leave able to name which of the three your current system is failing on.
Maintainability
The ease with which engineering and operations teams can keep the system running, understand it, and adapt it to new use cases over time, encompassing operability, simplicity, and evolvability.
Why it matters. A system that ships correct results but resists change quietly consumes your entire team's capacity in operational firefighting and fear-driven paralysis until no new use case is affordable.
Myth
Maintainability is something you clean up later through refactoring sprints and better documentation once the product stabilizes.
Reality
Maintainability is a set of structural properties baked into your data models, boundaries, and abstractions at design time; documentation and cleanup cannot retrofit simplicity into a system whose accidental complexity is already load-bearing.
- Break maintainability into operability, simplicity, and evolvability so you can diagnose which specific property is bleeding your team's time.
- Good abstractions are the primary tool against accidental complexity — a clean interface that genuinely hides mess is worth more than any amount of comments.
- Evolvability is decided by your data encoding and interface boundaries far more than by your code style, because those determine whether change requires coordinated migration.
The deep drill-down: 7 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Maintainability Three-Facet Audit” tool. Included when you buy this guide.
The rest of this section
the full written section · 4 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section helps you pick a structural and serialization model that matches how your data is actually queried and how its schema will change over time. You will learn to reason about relational, document, and graph models as answers to access patterns rather than as ideologies.
Data Model and Encoding Choice
The selection of how data is structured and serialized (relational, document, graph) and how it is encoded for storage and transmission, including schema evolution strategy.
Why it matters. The wrong model forces every future query and migration to fight the storage layer, embedding friction into every feature you ship for years.
Myth
Practitioners believe document (schemaless) models eliminate the pain of schema management.
Reality
Document stores are schema-on-read: the schema still exists, but it moves into your application code as implicit assumptions scattered across every read path. You trade one explicit schema for many implicit ones.
- Data locality is the real tradeoff of document models: great when you read the whole object, costly when you update a fragment.
- Schema evolution compatibility (forward and backward) is a first-class selection criterion, not an afterthought.
- Graph models pay off specifically when relationship traversal, not aggregate lookup, dominates your queries.
The deep drill-down: 7 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Data Model & Encoding Decision Sheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section explains how the engine underneath your database — LSM-tree, B-tree, or column store — determines write amplification, read latency, and analytic throughput. You will learn to read a workload and predict which internal structure serves it.
Storage Engine Design
The internal data structures and write/read strategies used to persist and retrieve data, such as log-structured (LSM-tree), page-oriented (B-tree), or column-oriented storage, optimized for transactional or analytic workloads.
Why it matters. The storage engine sets a hard ceiling on write and read performance that no amount of application tuning can lift once you have chosen wrongly.
Myth
Engineers assume LSM-trees are always faster than B-trees because they write sequentially.
Reality
LSM-trees excel at write throughput but pay compaction overhead that can stall writes under sustained load and make read latency unpredictable; B-trees give steadier, more predictable latency. The right choice depends on whether your bottleneck is write volume or latency variance.
- LSM-trees optimize write throughput at the cost of read and latency predictability; B-trees do the reverse.
- Column-oriented storage is the enabler for analytic queries because it reads only the columns a query touches.
- The engine choice is a workload commitment: pick after profiling your read/write mix, not before.
The deep drill-down: 8 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Storage Engine Selection Worksheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section walks you through single-leader, multi-leader, and leaderless replication and the synchronous/asynchronous choice that governs data loss and staleness. You will learn what each topology guarantees and what it silently forfeits.
Replication Strategy
The approach to keeping copies of data on multiple nodes, including single-leader, multi-leader, and leaderless replication, and synchronous versus asynchronous propagation of changes.
Why it matters. Your replication topology decides whether a failed node loses committed writes or merely loses availability — a difference your users will feel as either corruption or downtime.
Myth
Practitioners think adding read replicas gives them consistent reads for free.
Reality
Asynchronous followers lag the leader, so a user can write, then read from a replica and see stale or missing data — replication lag creates real consistency anomalies like reading your own writes disappearing. You must add read-your-writes and monotonic-read guarantees deliberately.
- GitHub Replication Lag IncidentCase study — A primary MySQL database replica failed during a period of high load.
- Setting Up a New FollowerProcess — To bring a new node online with an accurate copy of the database and have it start replicating from the leader.
- Synchronous vs. asynchronous is a durability-vs-availability dial, not a performance detail.
- Replication lag is a correctness problem requiring explicit read-your-writes and monotonic-read guarantees.
- Any topology with more than one writer forces you to own conflict resolution semantics.
The deep drill-down: 8 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Replication Strategy Selection Worksheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for · 2 tools for this section. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section covers how to split a dataset across nodes using key-range or hash partitioning, how to partition secondary indexes, and how to rebalance without downtime. You will learn to spread load evenly and avoid hotspots.
Partitioning Strategy
The method of splitting a large dataset across nodes, including key-range and hash partitioning, secondary index partitioning, and rebalancing approaches to spread load and storage.
Why it matters. A partitioning scheme that concentrates load on one node turns a distributed system back into a single-node bottleneck, negating the entire point of scaling out.
Myth
Engineers believe hash partitioning always distributes load evenly and eliminates hotspots.
Reality
Hash partitioning spreads keys evenly but destroys range-query efficiency and does nothing about a single hot key — a celebrity user or viral item still funnels all traffic to one partition. Skew lives in access patterns, not just key distribution.
- Hash partitioning trades away efficient range queries for even key distribution.
- A single hot key defeats any partitioning scheme and needs application-level splitting.
- Fixing partition count above node count makes rebalancing a matter of reassigning partitions, not rehashing data.
The deep drill-down: 7 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Partitioning Strategy Worksheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
strong · 1 source
- Designing Data-Intensive Applications
This section maps the isolation levels — read committed, snapshot isolation, serializability — onto the concurrency anomalies each prevents, and covers atomic commit across nodes. You will learn to pick the weakest level that is still correct for your invariants.
Transaction and Isolation Guarantee Level
The strength of safety guarantees provided for grouped reads and writes, ranging from weak isolation levels (read committed, snapshot isolation) to serializability and atomic commit across nodes.
Why it matters. Choosing an isolation level weaker than your invariants require lets concurrent transactions silently corrupt data in ways that surface only under load and are nearly impossible to reproduce.
Myth
Practitioners assume that if their database is 'ACID' and set to a named isolation level, concurrency anomalies cannot occur.
Reality
Most databases default to read committed or snapshot isolation, neither of which prevents write skew or lost updates on interdependent reads. The word 'isolation' is marketing until you know exactly which anomalies your chosen level actually excludes.
- Isolation Level Anomaly Decision TreeTemplate — A mental tool to decide if a weaker transaction isolation level is sufficient, or if serializability is required, by identifying potential race conditions.
- Two-Phase Commit (2PC) for Distributed TransactionsProcess — To ensure that the transaction commits on all nodes or aborts on all nodes, preserving atomicity.
- Every isolation level is defined by the specific anomalies it forbids, not by its reassuring name.
- Snapshot isolation stops most anomalies but permits write skew on interdependent decisions.
- Serializability is the only level that lets you reason about transactions as if they ran one at a time — pay for it only where invariants demand it.
The deep drill-down: 8 operational steps, a worked example from the source, 5 decision rules, 5 failure modes, and the “Isolation Level Selection Worksheet” tool. Included when you buy this guide.
The rest of this section
the full written section · 3 how-to steps · 2 pitfalls to watch for · 2 tools for this section. Included when you buy this guide.
Grounded in: Designing Data-Intensive Applications
The playbook — the whole process
Beneath the model sits the practical spine — 5 named, end-to-end processes the source books lay out. Here they are, in sequence, each broken into the steps you actually run.
The sequence — high level first
Illumination of the parts
Process 1 · named in the source
Automatic Leader Failover
To promote a follower to become the new leader so the system can continue accepting writes.
- 1
Determine the leader has failed, typically using timeouts on heartbeats.
- 2
Choose a new leader, often via an election among remaining replicas or appointment by a controller node.
- 3
Reconfigure client and follower nodes to send writes and fetch replication logs from the new leader.
- 4
Ensure the old leader, if it recovers, becomes a follower and recognizes the new leader's authority.
Process 2 · named in the source
Setting Up a New Follower
To bring a new node online with an accurate copy of the database and have it start replicating from the leader.
- 1
Take a consistent snapshot of the leader's database, noting the log position (LSN/binlog coordinates).
- 2
Copy this snapshot to the new follower node.
- 3
Connect the follower to the leader.
- 4
Request the replication log for all data changes that occurred since the snapshot was taken.
- 5
Apply the backlog of changes until the follower is fully caught up with the leader.
- 6
Continue processing the stream of new data changes from the leader as they happen.
Process 3 · named in the source
SSTable Compaction and Merging
To combine smaller, newer log segments into larger ones, reclaiming disk space by discarding overwritten and deleted values.
- 1
Open several sorted segment files (SSTables) for reading.
- 2
Read the files side-by-side, in a mergesort-like fashion.
- 3
Compare the first key in each input file.
- 4
Copy the lowest key to a new, merged output segment file.
- 5
If the same key appears in multiple input segments, keep the value from the most recent segment and discard older ones.
- 6
Repeat until all input files have been processed.
- 7
Atomically switch read requests to use the new merged segment and delete the old segment files.
Process 4 · named in the source
Two-Phase Commit (2PC) for Distributed Transactions
To ensure that the transaction commits on all nodes or aborts on all nodes, preserving atomicity.
- 1
Send a 'prepare' request from the coordinator to all participant nodes.
- 2
Wait for participants to vote 'yes' or 'no'. A 'yes' vote is a promise to commit if asked, and the participant must make the transaction's writes durable before voting.
- 3
If all participants vote 'yes', decide to 'commit'. If any participant votes 'no' or times out, decide to 'abort'.
- 4
Durably write the commit/abort decision to the coordinator's transaction log.
- 5
Send the decision to all participants, retrying forever until every participant acknowledges it.
Process 5 · named in the source
Partition Rebalancing (Adding a Node)
To move some partitions from existing nodes to the new node to distribute load evenly.
- 1
Tell the new node to steal partitions from existing nodes until load is balanced.
- 2
Copy the data for a partition from the current node to the new node over the network.
- 3
Continue serving read and write requests using the old partition assignment while the data transfer is in progress.
- 4
Once the data transfer is complete, atomically switch routing so that new requests for the moved partition go to the new node.
- 5
Delete the partition data from the old node.
What's underneath
What the field takes for granted
Every field runs on assumptions it rarely says out loud — the beliefs its advice quietly depends on. We surface the load-bearing ones, where they hide, and when they break. Most guides never tell you this.
Placing the idea
How it compares — and where else it applies
We don't just explain the idea in isolation. We place it: against the alternative it replaces, and beyond the domain it was born in. That's the difference between knowing a method and knowing when to reach for it.
How it compares
vs LSM-Trees vs. B-Trees
Both are key-value indexing structures.Both keep keys sorted, allowing for efficient range queries.
LSM-Trees are append-only, merging sorted files (SSTables) in the background. B-Trees update fixed-size pages in place.LSM-Trees are optimized for high write throughput. B-Trees are generally optimized for faster read performance.LSM-Trees can have higher write amplification due to compaction, but are often more compressible. B-Trees can suffer from internal fragmentation.
The choice is a trade-off dependent on the workload. LSM-Trees are good for write-heavy loads, while B-trees offer more predictable read latencies as they don't have compaction processes that can interfere with queries.
vs Document vs. Relational Data Models
Both are general-purpose models for storing structured data.Both can represent one-to-many and many-to-many relationships, though via different mechanisms (nesting vs. foreign keys).
Relational model enforces a schema-on-write and uses normalization. Document model is typically schema-on-read and encourages denormalization.Document model has better data locality for entire documents. Relational model requires joins to reconstruct document-like structures.Relational model has strong, mature support for joins. Join support in document databases is often weak or non-existent.
The book argues that neither model is superior and they are converging. The choice depends on the application's data structure: document models are good for self-contained tree-like data, while the relational model is better for highly interconnected data.
vs Single-Leader vs. Multi-Leader vs. Leaderless Replication
All are strategies for keeping copies of data on multiple nodes to provide fault tolerance and scalability.
Single-leader funnels all writes through one node, offering a simple consistency model but creating a single point of failure.Multi-leader allows writes on multiple nodes, improving write latency and datacenter failure tolerance, but requires complex conflict resolution.Leaderless replication (Dynamo-style) allows any replica to accept writes, prioritizing high availability but providing only weak eventual consistency and requiring quorums.
Each model represents a different point in the design space of distributed systems trade-offs. The book analyzes the failure modes and consistency guarantees of each in detail to help the reader make an informed choice.
vs MapReduce vs. MPP Databases
Both are capable of parallel query execution on large datasets distributed across a cluster.
MPP databases are monolithic, integrated systems with a SQL interface, optimized for structured analytics. MapReduce is a general-purpose programming framework on top of a distributed filesystem (HDFS).MPP databases require data to be loaded into their specific storage format and schema. The Hadoop ecosystem supports arbitrary data formats.MapReduce is designed to tolerate frequent task termination by materializing intermediate state to disk. MPP databases typically abort the entire query on node failure.
The Hadoop ecosystem is framed as a distributed 'operating system' that offers flexibility and supports diverse processing models, while MPP databases are specialized, high-performance appliances. The two are converging as dataflow engines add SQL interfaces and optimizers.
vs Distributed Transactions vs. Asynchronous Dataflow with Idempotence
Both are approaches to achieve correctness and data integrity when an operation must make changes across several systems or partitions.
Distributed transactions (like 2PC) use synchronous coordination to provide atomic commit and strong consistency (linearizability). They are brittle, operationally complex, and have high performance overhead.Asynchronous dataflow uses an event log as the source of truth, with idempotent consumers applying changes. This approach is loosely coupled, more fault-tolerant, and has better performance, but provides weaker timeliness guarantees.
The book advocates for the asynchronous dataflow approach, arguing that it provides sufficient integrity guarantees for many applications with better performance and operational characteristics than traditional distributed transactions. It separates the problem into 'integrity' (which must be strong) and 'timeliness' (which can often be relaxed).
Where else it applies
The model, taken beyond its home domain
Organizational Structure & Team Management
The principles of loose coupling and well-defined interfaces, discussed in the context of microservices and dataflow systems, can be applied to structuring engineering teams. By giving teams clear ownership of services or data products and defining how they interact (e.g., via an event log), organizations can reduce coordination overhead and scale development efforts more effectively.
Urban Planning and Smart Cities
A city can be modeled as a data-intensive system. Sensor data from traffic, public transit, and utilities can be treated as event streams. Stream processors can maintain materialized views of the city's state (e.g., traffic congestion maps). This allows for low-latency responses, like dynamic traffic signal timing, while batch processing on historical data can inform long-term planning.
Scientific Research (e.g., Genomics, Particle Physics)
The book mentions these domains as examples of large-scale data processing. The 'unbundling' approach is relevant: raw experimental data is the system of record (stored in a distributed filesystem). Various batch and stream processing jobs are run to transform, filter, and analyze this data, creating derived datasets for specific research questions, without altering the original raw data.
Personal Finance Management
The book's analogy to financial accounting and event sourcing can be applied directly. A user's financial life can be modeled as an immutable log of transactions (events). The current account balance, spending reports, and budgets are all materialized views derived from this log. This provides a clear audit trail and makes it easy to add new analytical features without changing the core transaction data.
Software Development Toolchains
A version control system like Git is a perfect example of an immutable, append-only log (the commit history). The current state of the code is a materialized view of that log. Continuous Integration (CI) systems are essentially stream processors that are triggered by new events (commits) and produce derived data (test results, build artifacts).
Movement III · The run-it-now depth
The Playbook
Practical tools and examples from this guide.
Frameworks
Unbundling the Database
A design philosophy for building data systems by composing specialized, loosely coupled components (event logs, stream processors, storage systems) rather than using a single monolithic database. Data flows between components via event streams, with transformations applied at each stage.
Start hereIdentify a derived data system, such as a search index or cache, that needs to be kept in sync with a primary database (system of record).
PathMove from dual writes or periodic batch ETL to a real-time change data capture (CDC) stream. Use the stream to update the search index. Gradually add more derived systems (materialized views, analytics models) as consumers of the same or subsequent streams.
- 1Establish a system of record and capture all writes to it as an immutable event log.
- 2Use stream processors to consume the event log and transform the data into models suitable for various read patterns.
- 3Write the transformed data (derived data) into specialized read-optimized systems like search indexes, caches, or materialized views.
- 4Build read services that query the derived data systems to serve user requests.
Reliability-Scalability-Maintainability (RSM) Analysis Framework
A mental model for evaluating and reasoning about the design of a data-intensive application. It encourages a structured approach to analyzing trade-offs by focusing on three key non-functional requirements.
Start hereFor any new system or feature, explicitly define expectations in terms of reliability (tolerating faults), scalability (coping with load), and maintainability (ease of operations, simplicity, and evolvability).
◆ The full 3-step framework — included with this guide purchase
Event Sourcing
An application design pattern where all changes to application state are modeled and stored as a sequence of immutable events. The current state is derived by replaying these events.
Start hereIdentify a core business entity and its state changes. Instead of designing a mutable database table for it, design a log to store events representing user actions.
◆ The full 4-step framework — included with this guide purchase
Case studies — including what didn't work
The Mailbox Model: How Twitter Traded Read Cost for Write Cost
Facing 300,000 home-timeline reads per second, Twitter abandoned read-time tweet merging for a precomputed cache — then learned that celebrities break the model.
This case shows how a single load parameter — the distribution of followers per user — should drive an architecture, and why the right answer is often a hybrid rather than a pure design. It's a foundational lesson in reasoning about scalability before choosing a solution.
The story, in brief
Abstract
Twitter's home timeline faced 300k read requests per second against an average of only 4.6k tweet posts per second. Rather than merging tweets at read time with an expensive join, Twitter precomputed each user's timeline via fan-out-on-write, trading cheap reads for far more expensive writes. Because follower counts vary wildly — some users exceed 30 million followers — Twitter ultimately adopted a hybrid that excepts celebrities from fan-out and merges their tweets in at read time.
Situation
Two of Twitter's main operations sat in tension. Users posted tweets at 4.6k requests/sec on average and over 12k at peak, while home timeline reads ran at 300k requests/sec. Simply handling 12,000 writes per second would have been fairly easy; the real challenge was fan-out — each user follows many people and is followed by many people. The first version of Twitter used approach 1: posting a tweet inserted it into a global collection, and reading a home timeline meant looking up everyone a user follows, fetching all their tweets, and merging them by time, expressible as a relational join across tweets, users, and follows. The systems struggled to keep up with the load of home timeline queries.
The decision
Twitter switched to approach 2. Instead of doing the work at read time, it maintained a cache for each user's home timeline — a mailbox of tweets per recipient. When a user posts, the system looks up all of that user's followers and inserts the new tweet into each of their timeline caches. The reasoning was quantitative: the average rate of published tweets is almost two orders of magnitude lower than the rate of home timeline reads, so it is preferable to do more work at write time and less at read time.
What happened
The trade worked for the common case but exposed a new cost. Posting a tweet now required a lot of extra work. On average a tweet is delivered to about 75 followers, so 4.6k tweets per second became 345k writes per second to home timeline caches. That average concealed the real problem: the number of followers per user varies wildly, and some users have over 30 million followers, meaning a single tweet could result in over 30 million writes to home timelines — all to be delivered within Twitter's five-second target.
Because of this skew, Twitter moved to a hybrid of both approaches once approach 2 was robustly implemented. Most users' tweets continue to be fanned out to home timelines at post time, but a small number of users with very large follower counts — celebrities — are excepted from fan-out. Tweets from any celebrities a user follows are fetched separately and merged into that user's timeline at read time, exactly as in approach 1.
Outcome
Read requests became cheap because their results were precomputed. Writes became far more expensive — 345k timeline writes per second at the average, and potentially over 30 million writes from a single celebrity tweet. The hybrid approach is described as able to deliver consistently good performance by combining precomputed timelines for ordinary users with read-time merging for the extreme fan-out cases.
The lesson
The decisive load parameter was not tweet volume but the distribution of followers per user, weighted by how often those users tweet, since that determines the fan-out load. Reasoning about which operation dominates — here, reads outnumbering writes by nearly 100 to 1 — pointed to precomputing at write time; recognizing the skew in that distribution pointed to exempting the extreme cases. No single pure architecture was correct across the whole user base.
How to apply it
- Identify the load parameter that actually dominates your system — the ratio of reads to writes, or the skew in a distribution — before choosing between read-time computation and write-time precomputation.
- When reads vastly outnumber writes, prefer doing more work at write time (precompute and cache results) so reads stay cheap.
- Check whether an average hides extreme cases; here 75 followers on average masked users with over 30 million followers, which changed the design.
- Consider a hybrid that treats the bulk of cases one way and the extreme outliers another, rather than forcing one pure model on all inputs.
- Set and hold to a concrete performance target (Twitter's five-second delivery window) so the write-side cost of fan-out stays bounded even for the largest accounts.
When the Wrong Replica Became Leader: GitHub's Primary-Key Collision
An automated failover promoted a lagging MySQL follower, whose stale auto-increment counter reissued primary keys already in use—corrupting data and exposing private records to the wrong users.
During failover, an out-of-date MySQL follower was promoted to leader. Because auto-incrementing key generation is local to each server, the new leader's counter lagged behind the old leader's and began reissuing primary keys that had already been assigned. Those keys were also used in Redis, so the reuse produced inconsistency between the two stores—and caused some private data to be disclosed to the wrong users.
◆ The full case — situation, decision, outcome, and the lesson — included with this guide purchase
When Deleted Items Come Back: Amazon's Shopping Cart and the Cost of a Naive Merge
Amazon built a database that never lost a write—which is exactly why items customers had removed kept reappearing in their carts.
To stay available, the system allowed concurrent writes and stored conflicting versions as separate siblings. Its conflict resolution logic merged carts by taking the union of items—which preserved additions but had no way to represent a removal. A deletion could be silently overwritten by a concurrent version that still contained the item.
◆ The full case — situation, decision, outcome, and the lesson — included with this guide purchase
The Minute That Had 61 Seconds
On June 30, 2012, a single extra second added to Coordinated Universal Time exposed a dormant assumption in the Linux kernel and hung applications across the internet simultaneously.
Many applications and kernel versions carried a dormant assumption that a minute never has more than 60 seconds. Because Coordinated Universal Time occasionally adds a leap second to stay in sync with Earth's rotation, this assumption was destined to break — and when it did, it broke everywhere at once, not on one machine but across many organizations.
◆ The full case — situation, decision, outcome, and the lesson — included with this guide purchase
Templates
Quorum Write/Read Formula
To configure the trade-off between consistency, availability, and latency in leaderless replication systems by ensuring an overlap between nodes that accept a write and nodes that are contacted for a read.
w + r > n Where: n = number of replicas w = write quorum (number of nodes that must acknowledge a write for it to be considered successful) r = read quorum (number of nodes that must respond to a read request) Example Configurations: - High read availability: w = n, r = 1 - High write availability: r = n, w = 1 - Balanced (common): n=3, w=2, r=2 or n=5, w=3, r=3
Isolation Level Anomaly Decision Tree
A mental tool to decide if a weaker transaction isolation level is sufficient, or if serializability is required, by identifying potential race conditions.
◆ The fillable template — included with this guide purchase
Items marked Paid are included when you buy this guide.
Reading well
How the author makes the case
Reading well means seeing how an argument is built, not just what it claims. Here are the moves this author uses to persuade you — the technique, where it shows up, and what it's doing to you. See the machinery, and you read everything more sharply.
storytelling
The recurring story of designing and scaling Twitter's home timeline is used to introduce and illustrate trade-offs between read-path and write-path complexity.
To make abstract architectural trade-offs concrete and memorable by grounding them in a well-known, real-world system.
metaphor
Comparing the Unix philosophy of pipes and small tools to the design of dataflow systems ('the garden hose'). Comparing a two-phase commit to a marriage ceremony.
To explain complex, abstract technical concepts by relating them to familiar, physical-world analogues, making them more intuitive and easier to understand.
pattern_repetition
The concepts of trade-offs, immutability, and dataflow are introduced early and then revisited in almost every chapter in different contexts (storage engines, replication, transactions, batch, and stream processing).
To build up a cohesive and powerful mental model for the reader. By seeing the same principles applied in various domains, the reader understands them more deeply and learns to generalize them.
simplification_of_complexity
Chapter 3 begins with a simple database implemented as two bash functions and then incrementally adds features like hash indexes, log compaction, and B-trees to explain why each component is necessary.
To deconstruct a complex system into its fundamental building blocks. This approach allows the reader to understand the rationale behind each feature, rather than being overwhelmed by the complexity of a fully-featured system.
emotional_appeal
In the final chapter, the author asks the reader to 'replace the word data with surveillance' and reflect on the ethical implications. He appeals to the reader's sense of responsibility for building a world that 'treats people with humanity and respect'.
To challenge the reader to think beyond the purely technical aspects of their work and to consider the societal and ethical impact of technology, framing it as a moral responsibility for engineers.
Movement IV
Reflect
Consider the book's evidence, limitations and how it compares with other sources.
How good is it — where the book stands against the field, what it leaves open, and when to trust it.
- — Its positioning, its critique, its blind spots
- — When to apply it — and when not
- — The evidence behind the advice
Book profile · in the corpus
This book’s model, against the corpus
9 of 13 constructs align with the field · 4 the book adds · 6 where it diverges · the field spans 41 constructs across 25 books
Shared with the corpus — corroborated by other sources
This book's own emphasis — where it's the authority
Where it diverges — the book and the field pull apart
The corpus adds — from 24 other sources this book doesn't cover
The full field guide folds in ideas this book doesn’t reach — drawn from 24 further sources and cited in the full model.
This book’s place in the corpus
Why the corpus guide, not just this book
This book stands on the shoulders of the field's data-architecture and system-reliability tradition, agreeing on the reliability/scalability/maintainability triad, but it is the clear authority on the distributed-systems internals — storage engines, replication, partitioning, transactions, consensus, and dataflow — that the field only names in passing. The reconciled field-guide still adds by situating these engineering constructs within the broader analytics lifecycle (governance, value, culture, ethics) that this narrowly technical book does not address.
This guide stands on the shoulders of this book and 24 other sources — every claim cited, the disagreements named.
Read it closely
The book, examined
Not a summary — a close analytical reading: how the book is built, what it leaves open, and where it falls short.
How it’s built — the argument in order
- 01Part I: Foundations of Data Systems — Establishes the three guiding concerns—reliability, scalability, maintainability—and the reasoning tools (load parameters, percentile latencies, fault vs. failure) that frame every later decision; then descends into data models and query languages, encoding/serialization for schema evolution, and storage engine internals (log-structured vs. B-tree), showing the trade-offs behind single-node design choices.
- 02Part II: Distributed Data — Extends the single-machine picture across multiple machines via replication (leader/multi-leader/leaderless and their consistency anomalies), partitioning (sharding strategies and rebalancing), transactions and isolation levels (from read committed to serializable), the hard truths of distributed systems (unreliable networks, clocks, process pauses, partial failures), and the theory tying linearizability, causality, and consensus together—showing what guarantees can and cannot be achieved.
- 03Part III: Derived Data — Synthesizes the book's argument by treating data as derived through transformations: batch processing (MapReduce and dataflow engines), stream processing (event logs, change data capture, event sourcing), and their unification into coherent architectures that achieve integrity scalably via asynchronous log-based dataflow and end-to-end identifiers—closing with the engineer's ethical responsibility.
What it leaves unsolved
How exactly should engineers weigh reliability vs. cost, consistency vs. availability, and timeliness vs. integrity for a given application?
The book explicitly holds that 'there is no single right solution' and teaches reasoning rather than answers, so it deliberately leaves the concrete trade-off decisions to the reader's judgment and context.
How do you deploy, operate, secure, and manage these systems in production?
The author openly excludes deployment, operations, security, and management from scope, calling them complex topics that deserve their own books—so the operational lifecycle behind reliability remains outside the analysis.
What should engineers concretely do about bias, surveillance, and privacy beyond acknowledging responsibility?
The ethics takeaway asserts responsibility but the book's technical framing offers no methodology for measuring or mitigating these harms, leaving the ethical obligation stated but not operationalized.
How should the many specific tools be chosen or configured in practice?
By design the book refuses to be a tutorial or give install/API instructions, so the gap between understanding principles and selecting/tuning an actual product is left to external documentation.
Where it falls short — a fair critique
By explicitly excluding deployment, operations, and security, the book presents an architecture-centric view of reliability that omits arguably the largest sources of real-world failure—human operational error and misconfiguration—despite naming human error as a fault category.
The framing that 'enduring principles remain true no matter which tool' sits in tension with the equally strong claim that 'there is no single right solution.' If trade-offs are always contextual and shifting, the boundary of what counts as an 'enduring principle' versus a contingent engineering fashion is asserted rather than rigorously demarcated.
The ethics-of-data section (bias, surveillance, privacy) is treated as a technical engineer's afterthought without engagement with the substantial legal, social-science, or policy literature on these questions, so its normative claims lack grounding equivalent to its technical rigor.
Anchoring examples like Twitter's fan-out on 30-million-follower celebrities risks overgeneralizing hyperscale patterns as canonical, precisely the 'you're not Google' premature-optimization trap the book itself warns against—readers may absorb extreme-scale designs as defaults.
The claim that strong integrity can be achieved scalably via asynchronous log-based dataflow plus end-to-end identifiers is presented as a favored resolution, but the failure modes, latency-window inconsistencies, and cases where distributed transactions remain necessary are underexplored relative to the confidence of the recommendation.
Before you apply it
Using it well
Where the method fits, who it’s for, and the honest case for and against — so you apply it where it works.
Is this book for you?
For you if
- You build or architect data-intensive backend systems
- You want principles that outlast specific tool versions
- You must justify database and consistency trade-offs
Skip it if
- You need a hands-on guide to one specific database
- You work only on small single-machine applications
- You want operations or security depth
Need first
- Working knowledge of at least one database and SQL
- Basic understanding of networks and concurrency
- Comfort reading technical algorithm descriptions
When it applies — and when it doesn’t
- Choosing a database or storage engine for a new application — the book's trade-off framing directly guides tool selection
- Designing replication and partitioning for scale — core chapters address distribution and consistency problems
- Reasoning about consistency guarantees in distributed systems — linearizability, causality, and consensus are treated precisely
- Integrating heterogeneous systems via event logs — CDC and event sourcing are explicitly recommended patterns
- Small app with modest data and no scaling needs — book warns against premature optimization for scale you lack
- Evaluating ethical/privacy implications of a data product — raised as responsibility but treated briefly, not comprehensively
- Needing step-by-step setup or API tutorials for a specific tool — explicitly not a tutorial for any particular software
- Planning deployment, operations, or security hardening — author states these are out of scope
The honest case
Strongest case for
- Enduring principles let you evaluate any tool despite churning buzzwords
- Trade-off framing prevents both premature optimization and naive tool choices
- Unifying batch and stream around deterministic dataflow simplifies architecture reasoning
- Reducing many distributed problems to consensus clarifies what is achievable
Strongest objection
- Principles without hands-on practice may not translate to correct production systems
- Excluding deployment, ops, and security omits where reliability often actually fails
- Fast-moving tooling can outpace the specific systems used as examples
Tensions — choices to make, not settled answers
The model's constructs are drawn from the source element(s); load-bearing constructs are corroborated across the shelf, emerging ones are flagged.
Ideas covered by the source notes
- Data Model and Encoding Choice
- Storage Engine Design
- Replication Strategy
- Partitioning Strategy
- Transaction and Isolation Guarantee Level
- Distributed Environment Unreliability
Movement IV · Measure · The evidence
The evidence behind the advice
We don’t just assert — we show the research the ideas rest on: the study, its key finding, what it means for you, and the citation to chase it yourself. Then a curated path to go deeper. Grounded, not hand-waved.
The studies
The empirical backing, with findings and citations — trace any claim to its source.
The fundamental limits of fault-tolerant consensus in an asynchronous system.
Impossibility of Distributed Consensus with One Faulty Process (FLP Result)
No such always-terminating consensus algorithm exists. Any consensus algorithm in this model must either risk never reaching a decision (violating termination) or risk nodes deciding on different outcomes if it doesn't wait for a reply (violating agreement).
Consensus is only solvable in practice by relaxing the assumptions of the asynchronous model, for instance by using timeouts to detect suspected crashed nodes (moving to a partially synchronous model).
Provides the theoretical foundation for why consensus is a hard problem and why many systems opt for weaker consistency models or use specific algorithms (like Paxos/Raft) that make certain timing assumptions.
Fischer, M. J., Lynch, N., & Paterson, M. S. (1985). Impossibility of distributed consensus with one faulty process. Journal of the ACM, 32(2), 374-382.
Implementing externally consistent (linearizable) distributed transactions at global scale.
Spanner: Google’s Globally-Distributed Database
By having transactions wait for the duration of the clock uncertainty interval before committing, Spanner can guarantee that transaction timestamps are consistent with causality. This allows it to use timestamps for concurrency control and provide linearizable transactions and consistent reads across datacenters.
Provides a new model for implementing strongly consistent distributed databases by making clock uncertainty a first-class citizen, challenging the idea that global consistency must be slow.
A key case study showing that strong consistency at global scale is achievable, and illustrating the deep connection between time, clocks, and consistency models. It provides a counterpoint to the idea that all large-scale systems must be eventually consistent.
Corbett, J. C., et al. (2012). Spanner: Google's globally-distributed database. In 10th USENIX Symposium on Operating System Design and Implementation (OSDI).
The ambiguity and insufficiency of the standard SQL transaction isolation levels.
A Critique of ANSI SQL Isolation Levels
The standard's definitions are ambiguous and based on informal English descriptions of phenomena (dirty reads, non-repeatable reads, phantoms) rather than a formal model. This has led to different database systems implementing the same named isolation level with wildly different guarantees.
The name of an isolation level is not enough; developers must understand the specific implementation and guarantees of their chosen database to avoid subtle concurrency bugs.
Central to the book's argument in Chapter 7 that weak isolation levels are complex and dangerous, and that 'ACID' is often just a marketing term. It justifies the need for a deep dive into concurrency control mechanisms.
Berenson, H., et al. (1995). A critique of ANSI SQL isolation levels. In ACM International Conference on Management of Data (SIGMOD).
Go deeper
A curated reading ladder — not a dump. Each with why it’s worth your time.
- Readings in Database Systems · Joseph M. Hellerstein and Michael Stonebraker
Provides historical context and original research papers for many of the foundational database concepts discussed in the book, such as B-trees, relational models, and query optimization.
- Concurrency Control and Recovery in Database Systems · Philip A. Bernstein, Vassos Hadzilacos, and Nathan Goodman
A classic textbook that provides the formal, theoretical underpinnings for the topics of transactions, concurrency control, and crash recovery discussed in Chapter 7 and 9.
- The Art of UNIX Programming · Eric S. Raymond
Explains the philosophy of composing small, single-purpose tools, which the book uses as a powerful analogy for designing dataflow systems and 'unbundling' databases.
- Weapons of Math Destruction · Cathy O'Neil
Directly cited in the final chapter, this book explores the ethical challenges and societal dangers of using algorithms and Big Data for decision-making, which is a key part of the book's closing argument.
- The Log: What Every Software Engineer Should Know About Real-Time Data's Unifying Abstraction · Jay Kreps
This influential blog post is a direct inspiration for the book's data integration and dataflow chapters, articulating the vision of the immutable log as the central component of a modern data architecture.
- Time, Clocks, and the Ordering of Events in a Distributed System · Leslie Lamport
This is the seminal paper that introduced logical clocks (Lamport timestamps) and the 'happens-before' relationship, which are foundational concepts for reasoning about causality and ordering in distributed systems, as discussed in Chapters 9 and 11.
Movement V
Measure
Use available assessments to reflect on what you have learned.
A way to gauge yourself against the book's model, and the instruments it gives you.
- — A self-check built from the book
- — Instruments and what you'd measure next
Learning curriculum
After this book, you can…
The book's learning objectives, classified by Bloom's taxonomy and ordered so each builds on the ones before it.
- explainAfter this book you can explain reliability, scalability, and maintainability as the three foundational concerns and articulate why they guide all data system design.Check: Define each concern in your own words and describe how each shapes a design decision for a given application scenario.
- characterizeAfter this book you can characterize a system's workload load in terms of read/write ratio, data volume, concurrency, and access patterns to describe its scaling challenges.Check: Given an application description (e.g., a social feed with fan-out), quantify load parameters and identify the dominant scaling bottleneck.
- distinguishAfter this book you can distinguish transaction isolation levels (read committed, snapshot isolation, serializable) and explain the concurrency anomalies each prevents.Check: Match given race-condition scenarios to the weakest isolation level that prevents them and explain the implementation mechanism.
- explainAfter this book you can explain how batch and stream processing derive data through deterministic, fault-tolerant transformations and describe how they can be unified.Check: Describe the shared principles of a batch job and a stream job and explain how immutable inputs enable recomputation in both.
- explainAfter this book you can explain the fundamental unreliability of distributed environments—dropped packets, clock drift, and process pauses—and why they make reasoning harder than single-machine systems.Check: Identify how each unreliability source could cause a specific failure in a described distributed operation.
- analyzeAfter this book you can explain how log-structured (LSM-tree) and page-oriented (B-tree) storage engines store and retrieve data and analyze their write/read trade-offs.Check: Trace a read and a write through each engine type and predict performance for a given read/write-heavy workload.
- analyzeAfter this book you can describe single-leader, multi-leader, and leaderless replication strategies and analyze the consistency problems each introduces.Check: Given a replication configuration and a fault, identify possible anomalies (stale reads, write conflicts) and propose mitigations.
- relateAfter this book you can relate linearizability, causality, and consensus, and determine when each ordering/agreement guarantee is required.Check: Given a requirement (e.g., uniqueness constraint, leader election), state which guarantee is needed and why weaker ones are insufficient.
- argueAfter this book you can argue that problems such as atomic commit, leader election, locks, and total order broadcast are reducible to consensus.Check: Take a given distributed-systems problem and demonstrate its equivalence or reduction to consensus.
- designAfter this book you can design a dataflow integration architecture using immutable event logs, change data capture, and derived data to keep heterogeneous systems in sync.Check: Produce an architecture diagram integrating multiple stores via a log-based source of truth and justify the total-order-of-writes decision.
- designAfter this book you can distinguish timeliness from integrity and design an asynchronous, log-based scheme with end-to-end operation identifiers to achieve scalable integrity without distributed transactions.Check: Given a workflow needing strong integrity, propose a log-based design with idempotent end-to-end identifiers and explain why it avoids synchronous coordination costs.
- selectAfter this book you can compare relational, document, and graph data models and encoding formats, and select one that supports schema evolution for a given use case.Check: For a stated requirement, choose a data model and encoding and justify the choice against backward/forward compatibility needs.
- evaluateAfter this book you can evaluate a proposed data architecture for accidental and inherent complexity and recommend abstractions, schema evolution, and loose coupling to improve maintainability.Check: Critique an existing system design for tight coupling and tangled dependencies and propose concrete evolvability improvements.
- judgeAfter this book you can judge the ethical consequences of data system design—bias, surveillance, privacy—and take responsibility for auditability and integrity verification.Check: Given a data system proposal, identify ethical risks and specify auditability and continuous integrity-checking measures to address them.
- selectAfter this book you can select and reason about key-range vs. hash partitioning, secondary-index partitioning, and rebalancing schemes for distributing a large dataset.Check: Design a partitioning scheme for a described dataset and justify it against skew, hot spots, and rebalancing cost.
How to measure it
Turning each idea into a measure
For each construct: how to operationalize it, the observable signals to look for, and how well it holds up.
Classify the dominant data model and encoding format used by a system, and document its schema evolution mechanism (e.g., schema-on-read vs schema-on-write).
- Use of relational tables, JSON/document stores, or graph databases
- Encoding formats such as Avro, Thrift, Protocol Buffers, JSON
- Presence of schema migration tooling
Categorical classification with supplementary documentation of evolution approach.
Valid as long as the dominant model reflects actual access patterns; hybrid systems require care. · Reliable when assessed from architecture documentation and code inspection.
Identify the storage engine type (log-structured, B-tree, column-oriented) and characterize its read/write performance via benchmarking.
- LSM-tree vs B-tree configuration
- Write amplification metrics
- Sequential vs random I/O patterns
- Compression and column layout
Categorical type plus continuous performance metrics.
Performance metrics must be measured under representative workloads. · Engine type is reliably determinable; benchmark results depend on test setup.
Categorize as single-leader, multi-leader, or leaderless, and record whether replication is synchronous or asynchronous, plus replication lag.
- Configured replication topology
- Failover behavior
- Measured replication lag
- Conflict resolution logic present
Categorical for model and synchrony; continuous for lag.
Valid from configuration and runtime metrics. · Replication topology is reliably observable; lag varies with conditions.
Identify the partitioning scheme (key-range, hash) and secondary index partitioning, and measure load distribution across partitions.
- Partition key assignment metadata
- Per-partition request and storage distribution
- Presence of hot spots or skew
- Rebalancing configuration
Categorical scheme plus continuous distribution metrics.
Skew measurement validly indicates partitioning effectiveness. · Reliably observable from partition metadata and monitoring.
Record the configured isolation level and atomic-commit mechanism, and verify via fault-injection tests for concurrency anomalies.
- Configured isolation level (read committed, snapshot, serializable)
- Presence of distributed transaction coordinators
- Observed concurrency anomalies under testing
Ordinal from weak to strong isolation plus categorical commit mechanism.
Configured level may differ from actual guarantees; testing improves validity. · Anomaly testing (e.g., Jepsen-style) provides reliable verification.
Aggregate observed network fault rates, clock skew measurements, and process pause durations into an environment unreliability profile.
- Network partition and packet loss events
- NTP-measured clock offset
- Garbage collection and scheduling pause logs
- Timeout-triggered failovers
Composite of continuous metrics; profile rather than single scalar.
Valid as a contextual moderator; difficult to fully capture all failure modes. · Individual metrics reliably measurable; composite requires consistent instrumentation.
Quantify via load parameters such as requests per second, dataset size, fan-out, and read/write mix.
- Requests per second metrics
- Total stored data size
- Concurrency levels
- Distribution of query types
Continuous metrics, multi-dimensional.
Choice of load parameters must match the system's bottleneck. · Reliably measured through system monitoring.
Document the consensus/ordering mechanism in use and verify its guarantees through linearizability and ordering tests under fault conditions.
- Use of consensus systems (ZooKeeper, etcd, Raft, Paxos)
- Linearizability test results
- Observed agreement under partition
- Ordering guarantees in logs
Categorical mechanism plus pass/fail verification of properties.
Linearizability testing provides strong validity evidence. · Behavioral testing is reliable but computationally expensive.
Characterize the integration architecture (dual writes vs log-based derivation) and measure derived-data freshness and consistency.
- Presence of log-based messaging (e.g., Kafka)
- Use of change data capture pipelines
- Derived view freshness / lag
- Reprocessing capability
Categorical architecture plus continuous freshness metrics.
Valid as indicator of integration robustness and evolvability. · Architecture reliably observable; freshness varies with load.
Assess through developer ratings of understandability and structural metrics such as coupling, dependency tangling, and change effort.
- Developer-reported difficulty understanding the system
- Coupling and dependency metrics
- Frequency of unexpected interactions/bugs
- Effort estimates for changes
Likert-style perceptual ratings combined with structural metrics.
Perceived complexity is a valid proxy for maintenance burden. · Self-report aggregated across developers improves reliability.
Measure via uptime, error and fault rates, mean time to failure, and incidence of data loss or corruption.
- Uptime percentage
- Error rates
- Incidents of data loss or corruption
- Successful recovery from faults
Continuous metrics aggregated over time periods.
Composite reliability requires capturing multiple fault types. · Archival operational metrics provide high reliability.
Measure throughput and response-time percentiles as load and resources are scaled.
- Requests handled per second at scale
- p95/p99 latency under increasing load
- Linear vs sublinear scaling with added nodes
Continuous performance metrics across load levels.
Must measure percentiles, not just averages, for validity. · Load testing provides reliable measurement.
Assess via operability metrics and team perceptions of ease of change, supplemented by change-effort tracking.
- Effort required to make changes
- Team-reported ease of operation
- Time to onboard new engineers
- Frequency of operational surprises
Combination of perceptual ratings and effort metrics.
Multi-dimensional construct; partial measures may understate it. · Aggregated team self-report and change tracking improve reliability.
Self-assessment
Where would you like to improve?
This is a structured self-diagnostic built from the model — a mirror for reflection, not a validated psychometric scale. For validated measurement, see the instruments below.
1 = Strongly Disagree · 7 = Strongly Agree
Proposed measures — starter instruments where no validated one was found
Data Model Fit Index
proposed · not validatedRate each observable statement on the scale below.
- Each new data domain has a documented rationale comparing relational, document, and graph options before schema design begins.
- Schema and encoding changes are versioned and validated against backward/forward compatibility rules prior to deployment.
- Query and access-pattern analysis is reviewed and updated whenever the data model is revised.
Scale: 1–7 (Strongly Disagree → Strongly Agree). Average the item ratings. This proposed index has no validated cutoff.
Storage Engine Suitability Index
proposed · not validatedRate each observable statement on the scale below.
- The choice between log-structured and page-oriented storage is documented with benchmarks reflecting expected read/write ratios.
- Compaction, indexing, and write-amplification metrics are monitored and reported on a regular cadence.
- Storage engine configuration changes are tested against representative workloads before being applied to production.
Scale: 1–7 (Strongly Disagree → Strongly Agree). Average the item ratings. This proposed index has no validated cutoff.
Replication Robustness Index
proposed · not validatedRate each observable statement on the scale below.
- The replication topology (single-leader, multi-leader, or leaderless) is documented along with the consistency guarantees it provides.
- Failover and leader-election procedures are tested through regular simulated node-failure drills.
- Replication lag and conflict-resolution events are logged and reviewed to confirm they stay within defined thresholds.
Scale: 1–7 (Strongly Disagree → Strongly Agree). Average the item ratings. This proposed index has no validated cutoff.
Sources
- Designing Data-Intensive Applications — Martin Kleppmann
The cheat sheet
Everything, on one page
One key takeaway from each section, with links to read more.
- Data Model and Encoding ChoiceData locality is the real tradeoff of document models: great when you read the whole object, costly when you update a fragment.
- Storage Engine DesignLSM-trees optimize write throughput at the cost of read and latency predictability; B-trees do the reverse.
- Replication StrategySynchronous vs. asynchronous is a durability-vs-availability dial, not a performance detail.
- Partitioning StrategyHash partitioning trades away efficient range queries for even key distribution.
- Transaction and Isolation Guarantee LevelEvery isolation level is defined by the specific anomalies it forbids, not by its reassuring name.
- Distributed Environment UnreliabilityYou cannot detect failure directly — you can only observe the absence of a response, which is ambiguous.
- Workload LoadLoad is a set of parameters; name the one that actually drives cost before scaling.
- Consensus and Ordering MechanismLeader election, atomic commit, and uniqueness constraints are all consensus in disguise — solve them with one proven mechanism.
- Dataflow Integration ApproachDerived data flowing from a single log is reproducible and self-healing; dual writes are not.
- System ComplexityAccidental complexity is removable; inherent complexity is not — knowing which is which directs your effort.
- ReliabilityReliability is fault tolerance, not fault avoidance — assume components will fail and contain the damage.
- ScalabilityScalability is always along a named dimension; 'is it scalable?' is an ill-formed question.
- MaintainabilityBreak maintainability into operability, simplicity, and evolvability so you can diagnose which specific property is bleeding your team's time.
Publication details
Consult the sources listed in this guide for further reading. Edition 1 · Updated 2026-08-19.