A study guide for Chapter 5 of Designing Data-Intensive Applications by Martin Kleppmann. It explains how to keep copies of the same data on several machines, and what goes wrong when the copies differ. It uses simple English, diagrams, examples, and tools that you can use.
Reading time: about 70 minutesBefore this: Part I (chapters 1 to 4). This is the first chapter of Part II.
What you will learn
Why you copy data to several machines, and the three reasons for it.
The three main replication methods: single-leader, multi-leader, and leaderless.
Why an asynchronous follower can show old data, and three guarantees that prevent the worst surprises.
How two writes at the same time create a conflict, and how to detect and merge them.
How quorums (w and r) decide how many copies must answer.
The ideas and facts come from the book. The code, examples, and drawings are new. The boxes named "Update since the book" come from public documentation.
Story first · Chapter 5
The courier and the ledger
Before the rules, meet the cast. This is a story about a village message that three couriers must keep the same. It is original art in paper-cut style. The characters are invented for this story and are not from any game or comic.
Ren, the leader. Writes every change first, in order, in the ledger.
Mio, a fast courier with cat ears and a quick route.
Gor, a strong courier whose road is often blocked.
Sora, a reader from the village who asks for the latest news.
1. The leader writes the news The bridge is closed. Ren is the leader, so Ren writes the change first, as version 7 in the ledger. The ledger keeps the order of changes.2. Couriers carry copies out Ren sends a copy to Mio and to Gor. Gor's road is blocked by a fallen tree, so Gor's copy is late. For a while, Gor still holds version 6.3. Write counts after two copies The rule is W = 2 of 3. Ren and Mio both hold version 7, so the write counts, and the village is told 'OK'. Gor will catch up later.4. A reader asks two couriers Sora wants the latest message, so Sora asks two couriers (R = 2). Gor says version 6, Mio says version 7. Sora keeps the newest: version 7. Two of three is more than half, so the two groups always overlap.5. What if the reader asks only one? Now Sora asks only Gor (R = 1). Gor's copy is still version 6. The groups do not overlap, because 2 + 1 = 3 is not more than 3. The reader gets stale news.
Your turn: change the rules
Gor's copy is always late in this story. Ren and Mio always hold the new message. Choose how many couriers must confirm a write (W), and how many a reader asks (R). Watch the story.
1. Why replicate?
Replication means that you keep a copy of the same data on several machines connected by a network. Each machine that holds a copy is a replica. There are three reasons to do this:
Latency
Put the data near the users. A user in Mumbai reads from a server in Mumbai, not in Virginia.
Availability
If one machine (or a whole data center) fails, the others keep serving the data.
Read throughput
Many replicas can answer read requests. One machine would be too slow.
In this chapter, each machine can hold the whole data set. Chapter 6 covers partitioning (sharding), which splits data that is too big for one machine. Here is the key point: if the data never changes, replication is easy. You copy it once. All the difficulty comes from changes. Every write must reach every replica, and it must reach them in a sensible order.
Three algorithms do this, and almost all databases use one of them:
Approach
Who accepts writes?
Examples
Single-leader
One leader. Followers copy its changes.
PostgreSQL, MySQL, MongoDB, Kafka
Multi-leader
Several leaders, often one per data center.
Tungsten, BDR for PostgreSQL, CouchDB
Leaderless
Any replica, directly from the client.
Dynamo, Riak, Cassandra, Voldemort
2. Leaders and followers
The most common method is leader-based replication. Also called master–slave, or active/passive.
One replica is the leader (or primary). All writes go to the leader. The leader writes the new data to its own storage first.
The other replicas are followers (read replicas, secondaries, hot standbys). The leader sends each change to its followers in a replication log. A follower applies the changes in the same order as the leader.
A client can read from the leader or from any follower. But writes are accepted only by the leader.
Figure 1. Single-leader replication. My own drawing of the book's Figure 5-1.
Many databases use this: PostgreSQL (since version 9.0), MySQL, Oracle Data Guard, and SQL Server AlwaysOn. Some NoSQL systems use it too, such as MongoDB and RethinkDB. Message brokers such as Kafka and RabbitMQ (in highly available queues) use it. So do network filesystems and DRBD.
Synchronous or asynchronous replication?
Here is a website example. A user changes their profile picture. The client sends the change to the leader. The leader sends it to the followers. Then the leader tells the client that the update worked. The question is: does the leader wait for the followers before it says "OK"?
Try it: what survives a leader crash?
Choose the replication mode. Then press "Leader crashes now". The user has been told "saved" for the write. Does the new leader still have it?
Here is the trade-off:
Synchronous: the follower has an up-to-date copy. If the leader dies, the write is safe. But if the synchronous follower is slow or down, all writes wait, or fail. One node outage stops the whole system.
Asynchronous: the leader keeps working even if all followers fall behind. But a write that the client was told about can be lost if the leader dies before it is copied. So the write is not durable, even after a success message.
In practice, one follower is often synchronous, and the others are asynchronous. If the synchronous follower slows down, an asynchronous one takes its place. This gives an up-to-date copy on at least two nodes. People call this semi-synchronous.
Asynchronous replication is still very common
Losing durability sounds bad. But asynchronous replication is used widely, especially with many followers or followers in other regions. The next section explains the price you pay for that.
Setting up a new follower
You cannot copy the data files while the database is changing. The files would show different parts of the data at different times. So you do this, without downtime:
Take a consistent snapshot of the leader. Most databases can do this for backups, without locking everything.
Copy the snapshot to the new follower.
The follower asks the leader for every change since the snapshot. The snapshot must be tied to an exact position in the replication log. PostgreSQL calls this the log sequence number. MySQL calls it the binlog coordinates.
When it has processed the backlog, it has caught up. Then it follows the live stream.
Node outages and failover
Nodes fail, and they also go down for planned work, such as a security patch. The goal is that the system keeps working, and the impact stays small.
Follower failure: catch-up recovery
Each follower keeps a log of the changes it received. After a crash or network break, it knows the last change that it applied. It asks the leader for everything after that point. Then it is caught up again.
Leader failure: failover
If the leader fails, one follower must become the new leader. Clients must send their writes to the new leader. The other followers must follow the new leader. This is failover. It can be manual, or automatic. An automatic failover does these three steps:
Detect that the leader failed. There is no perfect way. Most systems use a timeout. If a node does not answer for, say, 30 seconds, it is assumed dead.
Choose a new leader. By an election, or by a controller node. The best choice is the replica with the most recent data, to lose as little as possible. Agreement is a consensus problem (Chapter 9).
Reconfigure the system. Clients use the new leader. The old leader, if it comes back, must accept that it is now a follower.
Try it: the timeout dilemma
A short timeout finds a dead leader fast. But it also causes false alarms when the leader is only slow. Move the slider.
Failover can go wrong in four ways, and each one is a real risk:
Lost writes. With asynchronous replication, the new leader may not have all the writes of the old one. What happens when the old leader comes back? The usual answer is to discard its unreplicated writes. That can break users' expectations about durability.
Other systems get out of step. At GitHub, an out-of-date MySQL follower became leader. Its auto-increment counter was behind, so it reused some primary keys. Those keys were also used in a Redis store. The result: some private data was shown to the wrong users.
Split brain. Two nodes both believe they are the leader. If both accept writes, data is lost or corrupted. Some systems shut one node down when they see two leaders. If this is not designed well, both nodes can shut down.
The timeout is hard to choose. A long timeout means a slow recovery. A short timeout causes needless failovers. A load spike can then make things worse. For this reason, many operations teams prefer manual failover.
Real example
Example: promoting a follower safely
Three replicas: A (leader), B, and C. B has received everything from A. C is 2 minutes behind. A crashes. The best new leader is B, because it has the most recent data. If C is promoted, the 2 minutes of writes stay on A. When A comes back, those writes are either discarded or must be merged by hand.
How replication logs work
How does the leader send its changes? There are several methods.
what the leader sends (example)
-- The leader logs the SQL text of each write:
INSERT INTO orders (id, created) VALUES (42, NOW());
UPDATE accounts SET balance = balance - 10 WHERE id = 7;
-- Problems:
-- NOW() and RAND() give different values on each replica.
-- "UPDATE ... WHERE" depends on the data already there.
-- Triggers and stored procedures can have side effects.
-- Fix: the leader replaces NOW() with a fixed value before it logs.
what the leader sends (example)
-- The leader sends the bytes of its storage log (Chapter 3):
-- "write these bytes to disk block 1830 of file 16384"
--
-- Followers build the same data structures byte for byte.
-- Works well (PostgreSQL, Oracle), but the replica must run the
-- same storage format. Upgrading to a new version often needs downtime.
what the leader sends (example, one record per changed row)
{ "op": "insert", "table": "orders", "row": { "id": 42, "created": "2026-10-08T10:00Z" } }
{ "op": "update", "table": "accounts", "key": { "id": 7 }, "set": { "balance": 90 } }
{ "op": "commit", "txid": 9981 }
-- Independent of the storage format. Old and new versions can talk.
-- Easy for other programs to read (change data capture, Chapter 11).
triggers/orders_audit.sql (example file)
CREATE TRIGGER orders_audit
AFTER INSERT OR UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION write_to_change_table(); -- the app's own copy logic
-- More flexible: copy only some rows, or to another database type.
-- But more overhead, and more bugs, than built-in replication.
Each method has a trade-off. Statement-based replication is compact, but breaks easily. WAL shipping is precise, but it ties the replicas to one storage format. Logical logs are the most flexible, because the format is separate from the storage. Trigger-based replication gives the most control, and it is the most work.
Update since the book
PostgreSQL now has logical replication built in. It publishes changes per table, and a subscriber applies them. This is the logical approach from the book. Quorum-based synchronous replication is also in PostgreSQL. You write ANY 2 (s1, s2, s3) in synchronous_standby_names, and each commit waits until any 2 of the 3 standbys confirm it. MySQL uses row-based replication by default, when a statement is not deterministic. Check your version's documentation before you choose a setting.
In simple words
One leader takes writes. Followers copy its log in order.
Synchronous: safe, but slow or blocked when a follower is down. Asynchronous: fast, but the latest writes can be lost.
Failover is hard: lost writes, split brain, and wrong timeouts.
3. Problems with replication lag
Asynchronous followers are behind the leader by a small time. This is the replication lag. Normally it is under a second. Under heavy load or network trouble it can grow to minutes.
A follower shows old data while it is behind. If you run the same query on the leader and on a follower, you can get different answers. This is only temporary: when writes stop, the followers catch up. Databases call this eventual consistency. The word "eventually" is vague on purpose. There is no upper limit on the lag.
Many developers did not expect this. They built apps as if the database were one machine. The next three guarantees describe the most common surprises.
Reading your own writes
A user submits a comment, then reloads the page. If the reload reads from a lagging follower, the comment is missing. The user thinks the data was lost. This is a read-after-write problem. You need read-your-writes consistency: a user always sees their own updates. Other users may still see old data for a while.
Ways to get it:
Read from the leader for data that the user can change. A user's own profile is an example: only the owner edits it.
Read from the leader for a while after an update. For example, one minute.
Track the time or log position of the user's last write. Serve reads only from replicas that have reached that position, or wait for them.
Across devices, the last-write time must be stored centrally. And the phone and the laptop may route to different data centers.
Monotonic reads
A user refreshes a page. The first request goes to a fresh follower and shows a new comment. The second goes to a lagging follower and the comment has gone. Time seems to go backward. Monotonic reads is the guarantee that this does not happen: once you have read a value, later reads do not return an older value. It is weaker than strong consistency, but stronger than plain eventual consistency.
A simple way: send each user to the same replica every time, for example by hashing the user ID. If that replica fails, the user moves to another replica.
Consistent prefix reads
Mr. Poons asks: "How far into the future can you see, Mrs. Cake?" Mrs. Cake answers: "About ten seconds usually." These sentences have a cause and effect. Now imagine an observer who reads Mrs. Cake's answer from a fast partition, and Mr. Poons's question from a slow one. The observer sees the answer before the question. This is a causality violation.
Consistent prefix reads guarantees that if a sequence of writes happened in one order, readers see them in that order. A single partition does this automatically. Problems appear in partitioned databases, where different partitions lag by different amounts. Fixes: put causally related writes in the same partition, or track dependencies explicitly.
Try it: which guarantee prevents each anomaly?
Choose a guarantee for each anomaly. The explanation shows if it was right.
Try it: lag simulator
Move the lag. A user posts a comment at time 0, then reloads at time 1 second. Turn on the fixes and see what the user sees.
src/comments/read-comments.ts (example file)
// Read-your-writes: the author always reads their own recent posts from the leader.
async function readComments(postId: string, viewer: User) {
const fromLeader = viewer.lastWriteAt && Date.now() - viewer.lastWriteAt < 60_000;
const db = fromLeader ? leader : pickReplica(viewer.id); // pinned replica: monotonic reads
return db.query("SELECT * FROM comments WHERE post_id = $1 ORDER BY created_at", [postId]);
}
In simple words
Read your writes: reload shows what you just wrote.
Monotonic reads: a later read is never older than an earlier one.
Consistent prefix: answers never appear before their questions.
Pinning a user to one replica, and reading own data from the leader, are cheap fixes.
4. Multi-leader replication
One leader is a bottleneck. All writes must go through it. If you cannot reach the leader, you cannot write. The next idea: let more than one node accept writes. Each leader sends its changes to the others. Each leader is also a follower of the others. This is multi-leader replication, also called master–master or active/active.
Use cases
Inside one data center, multi-leader rarely pays off, because it adds complexity. It makes sense in three cases:
Several data centers. Each data center has a leader. Writes are local and fast. Changes go to the other data centers in the background. A data center can fail, and the others keep working. A slow or broken link between data centers does not block writes.
Offline operation. A calendar on your phone, laptop, and tablet is a leader on each device. You can add a meeting with no network. When you connect, the devices sync. Lag can be hours or days. CouchDB is built for this.
Collaborative editing. Google Docs and Etherpad let many people edit at once. You can lock the document (like single-leader with transactions), or make the unit of change very small (a keystroke) and resolve conflicts afterward.
Try it: single-leader against multi-leader across data centers
Two data centers, Mumbai and Virginia. The network between them takes the time you choose. Compare the time a user waits for a write.
Write from Mumbai
ms wait for the user
If the link goes down
The downside is serious. The same data can be changed in two places at the same time. Those changes conflict. Multi-leader replication is often called dangerous territory. Auto-increment keys, triggers, and constraints can behave badly when several leaders are involved. Most teams avoid it unless they need it.
Handling write conflicts
Two users edit a wiki page title at the same time. User 1 changes it from "A" to "B" on leader 1. User 2 changes it from "A" to "C" on leader 2. Both writes succeed locally. The conflict appears only when the changes are exchanged. With one leader, the second writer would wait or be rejected. With several leaders, both succeed. You learn about the conflict later, when it may be too late to ask the user.
Figure 2. The conflict from the book's wiki example (Figure 5-7). My own drawing.
Avoid conflicts first
The simplest strategy: make sure all writes for one record go to the same leader. For example, route each user's requests to their "home" data center. Then, for that user, the system acts as single-leader. This breaks when the leader must change, for example after a data-center failure.
Converge to one value
There are four common ways to reach one final value:
Method
How it works
Trade-off
Last write wins (LWW)
Give each write a timestamp or unique ID. The highest one wins.
Popular, but loses data. Several writes that were all reported as successful are thrown away.
Highest replica ID wins
Writes from the higher-numbered replica always win.
Also loses data.
Merge the values
Combine them, for example sorted and joined: "B/C".
No loss, but the merge must make sense for your data.
Keep all, resolve later
Store all conflicting values. Show them to the user or to the app to resolve.
No loss. More work for the application.
Most multi-leader tools let you write the rule in code. It can run on write (in the background, fast, cannot ask the user) or on read (all versions go to the app, which decides, then writes the result back). Conflicts are resolved for one row or document at a time. A transaction that changes several rows is not one unit for conflict resolution.
Example: the shopping cart that lost deletions
Amazon once had a cart rule that kept added items, but not removed ones. Customers saw items come back into their carts after deleting them. Custom merge rules are powerful, and they are easy to get wrong.
Try it: pick a conflict rule for the wiki title
Choose a rule. Press the button to replicate both leaders. See whether they agree, and what is lost.
Leader 1 ends with
Leader 2 ends with
Synchronous conflict detection gives up the point
You could wait for every leader to confirm before you say "OK". But then the write is only as fast as the slowest link. You might as well use single-leader replication.
Replication topologies
A topology is the path that writes take from one node to another. With two leaders, there is only one: each sends to the other. With more leaders, there are several choices.
Figure 3. Three topologies from the book (Figure 5-8). My own drawing.
Circular (MySQL's default): a write may pass through several nodes. Each write is tagged with the IDs of the nodes it passed through. A node ignores a write that carries its own ID, so there are no endless loops. But if one node fails, the circle breaks.
Star: simple, but the root is a single point of failure. It can be generalized to a tree.
All-to-all: the most fault-tolerant, because messages can take different paths. But some links are faster, so writes can overtake each other.
Overtaking causes a real problem. Client A inserts a row on leader 1. Client B updates that row on leader 3. Leader 2 may receive the update first. From its view, the update is for a row that does not exist. Timestamps do not solve this, because clocks are not perfectly in sync (Chapter 8). The book's answer is version vectors, shown below.
5. Leaderless replication
The last approach drops the leader completely. The client sends a write to several replicas at once. Or a coordinator node does it for the client. No node decides the order of the writes. This style is called Dynamo-style, after Amazon's Dynamo system. Riak, Cassandra, and Voldemort use it.
Writing when a node is down
Imagine three replicas, and one is rebooting. There is no leader, so there is no failover. The client writes to all three in parallel. Two accept. The third misses the write. If the client needs only two acknowledgments, the write succeeds. The client ignores the missed one.
When the third node comes back, it has stale data. Reads may return it. So a read also goes to several nodes in parallel, and the client uses version numbers to pick the newest value. Two mechanisms bring the stale node up to date:
Read repair. When a read finds a stale replica, the client writes the newer value back to it. Works well for data that is read often.
Anti-entropy. A background process compares replicas and copies missing data. It does not follow any order, so it can take a long time. Values that are rarely read can stay stale for a long time.
Figure 4. A write with w = 2 of n = 3, while replica 3 is down. My own drawing of Figure 5-10.
Gossip: how a rumor spreads
Twelve nodes. One node starts with a new value. Each round, every node that has the value tells a few random neighbors. Change how many each node tells, or split the network in two. Watch how many nodes know the value after each round.
Play · the courier and the ledger
Play the replication story on a map
The same cast as the story above. Ren writes version 7, and the write counts after 2 couriers hold it. Sora asks couriers for the latest version. Block Gor's road to see what a lagging copy does to a read.
Everyone holds version 6. Ren is the leader.
Quorums for reading and writing
How many replicas must agree? With n replicas:
A write needs w acknowledgments.
A read asks r replicas.
If w + r > n, then the set of nodes that got the write and the set you read must overlap in at least one node. That node has the latest value. This is the quorum condition. A common choice is n = 3 with w = r = 2. Another is n = 5 with w = r = 3.
The quorum condition also tells you how many failures you survive:
With n = 3, w = 2, r = 2: one node can be down. Reads and writes still work.
With n = 5, w = 3, r = 3: two nodes can be down.
With w = n and r = 1: reads are fast, but one failed node stops all writes.
Try it: quorums with n replicas
Choose n, w, and r, then choose which replicas are down. The write is acknowledged by the first w available replicas (green). A read asks r replicas (outlined). Try w = 1 and r = 1 to see a stale read.
Limits of quorums and sloppy quorums
Quorums look like a guarantee. They are not one. Even with w + r > n, you can read stale values:
Concurrent writes: it is not clear which came first. Only merging is safe. A timestamp (LWW) can lose writes because of clock skew.
A write runs at the same time as a read. The read may see the new value on some replicas and not others.
A write succeeded on fewer than w nodes, and it was reported as failed. It is not rolled back. A later read may return it.
A node with the new value fails, and is restored from an old copy. The count of new copies can fall below w.
Most quorum systems therefore do not give you read-your-writes, monotonic reads, or consistent prefix reads by default. Stronger guarantees need transactions or consensus (Chapters 7 and 9).
Now the sloppy quorum. Suppose the home nodes for a key are unreachable. You can (a) return an error, or (b) accept the write on any reachable nodes, even ones that are not home nodes. Option (b) is a sloppy quorum. When the home nodes come back, the temporary copies are sent to them. This is hinted handoff.
Analogy from the book
You lock yourself out of your house. You wait on the neighbor's couch. Later you go home, and the neighbor asks you to leave. The couch was a temporary home.
A sloppy quorum increases write availability: as long as any w nodes are up, you can write. But it breaks the overlap. The latest value may sit outside the home nodes, so a read of r home nodes can miss it. A sloppy quorum is only a promise that the data is stored on w nodes somewhere. Riak enables it by default. Cassandra and Voldemort disable it.
Multi-datacenter operation with leaderless replication
Cassandra and Voldemort count the replicas in all data centers in n. The client waits only for a quorum in its local data center. Writes to the other data centers happen in the background. Riak keeps client traffic in one data center, and copies between clusters asynchronously.
Detecting concurrent writes
Two clients write the same key at the same time, to a three-node store. Client A's write reaches node 1 first, and node 2 gets A then B, while node 3 gets B then A. Each node sees a different order, and nobody has a global clock. If each node just keeps the last value it received, the nodes stay different forever.
The common fix is last write wins: attach a timestamp and keep the biggest. This is simple, and Cassandra uses it. But the writes are concurrent*, so neither one happened "first". LWW silently drops one of two successful writes. It can also drop writes that are not concurrent, when clocks are skewed. LWW is fine when losing data is acceptable, for example in a cache. Another safe trick: write each key only once, and never update it. Cassandra users often use a UUID as the key.
The happens-before relationship
What is concurrency? Operation A happens before B if B knows about A, or depends on A, or builds on A. Two operations are concurrent if neither happens before the other. Exact clock time does not matter. Two events a few milliseconds apart can still be concurrent if the network hid one from the other.
Try it: happens before, or concurrent?
Read each case. Decide the relation between the two operations.
Version vectors: capturing the dependencies
The book's example uses one shopping cart on one replica. Two clients add items. The server must decide which writes overwrite others and which are concurrent. The trick: every write carries the version number that the client read before it wrote. Here are the five steps from the book. Press "Next step" to follow them.
Try it: a shopping cart with versions
The server keeps all values that are not yet overwritten, called siblings. A write that includes the version it read overwrites only the values it had seen.
The rules the server follows:
The server gives each key a version number that goes up with every write. A read returns all values not yet overwritten, plus the latest version.
A client must read before it writes, and it must merge the values it got.
When a write with version v arrives, the server removes all values with version v or lower, because the client has merged them. It keeps the values with a higher version, because they are concurrent.
A write without a version is concurrent with everything. It overwrites nothing, and it comes back as one more sibling.
Siblings are merged by the application. For a cart, the simple merge is the union. But union has a flaw: if you remove an item in one sibling, it returns in the union. The fix is a tombstone: a marker that says "removed at version v". Riak's CRDT data types merge siblings automatically, and keep deletions.
Version vectors for many replicas
With several replicas and no leader, one version number per key is not enough. Each replica keeps a counter for itself and remembers the counters of the others. The set of counters is a version vector. Riak's dotted version vector is a refinement. Riak calls the encoded vector the causal context. A client that read from one replica and wrote to another is still safe. The worst result is siblings, and no data is lost if you merge them.
Try it: compare two version vectors
Each vector has one counter per replica (A, B, C). Vector X happened before Y if every counter in X is less than or equal to Y's, and at least one is less. If neither is smaller in all places, the writes are concurrent.
src/versions/compare.ts (example file)
type VV = Record<string, number>; // replica ID to counter
// Returns "before", "after", "equal", or "concurrent".
function compare(x: VV, y: VV): string {
const ids = new Set([...Object.keys(x), ...Object.keys(y)]);
let xLess = false, yLess = false;
for (const id of ids) {
const a = x[id] ?? 0, b = y[id] ?? 0;
if (a < b) xLess = true;
if (b < a) yLess = true;
}
if (xLess && yLess) return "concurrent"; // neither knows the other
if (xLess) return "before";
if (yLess) return "after";
return "equal";
}
Update since the book
Amazon's DynamoDB has moved away from the leaderless model in its public product. Its global tables use last-writer-wins conflict resolution by default, and the timestamp is the key rule. Many databases now offer CRDTs (for example Redis Enterprise and Riak). Using a conflict rule means you must test it with concurrent writes, because a timestamp rule can silently drop data.
In simple words
Multi-leader: writes are fast and local, but concurrent writes conflict. Pick a rule that loses no data.
Leaderless: the client writes to many replicas. With w + r > n, you usually see the latest value.
Concurrent writes: keep siblings and merge them. Version vectors tell you which writes overwrote which.
6. Summary and glossary
Replication has four goals: high availability, disconnected operation, low latency, and read scalability. It sounds simple, but it needs careful thinking about concurrency and about everything that can go wrong.
Methods compared
Single-leader
Multi-leader
Leaderless
Who accepts writes
One leader
Several leaders
Any replica (or a coordinator)
Failover needed?
Yes, when the leader fails
No, other leaders continue
No failover
Concurrent writes
Blocked or rejected by the leader
Conflict, resolve later
Siblings, merge later
Read consistency
Leader reads are current. Follower reads lag.
Depends on the rule
Quorum (w + r > n) gives usually current reads
Typical use
Most relational databases
Multi-datacenter, offline apps
High availability, large clusters
Glossary
Term
Simple meaning
Replica
A node that holds a copy of the data.
Leader, follower
The node that takes writes, and the nodes that copy its changes.
Replication log
The ordered list of changes that the leader sends.
Synchronous, asynchronous
The leader waits for the follower's confirmation, or does not wait.
Semi-synchronous
One synchronous follower, the others asynchronous.
Failover
Promoting a follower to be the new leader.
Split brain
Two nodes both believe they are the leader.
Replication lag
How far a follower is behind the leader, in time.
Eventual consistency
Replicas agree after writes stop, with no set time limit.
Read-your-writes
A user always sees their own updates.
Monotonic reads
A user never reads an older value after a newer one.
Consistent prefix reads
Writes appear in the order that they happened.
Multi-leader
More than one node accepts writes.
Conflict
Two concurrent writes to the same data.
Convergence
All replicas reach the same final value.
Last write wins (LWW)
Keep the write with the biggest timestamp. Can lose data.
Topology
The paths along which writes flow between leaders.
Leaderless, Dynamo-style
Any replica accepts writes. No leader.
Quorum (w, r, n)
Number of acks for a write, number of replies for a read, and number of replicas. Overlap if w + r > n.
Read repair
A read writes the newest value back to stale replicas.
Anti-entropy
A background process that copies missing data between replicas.
Sloppy quorum, hinted handoff
Writes go to any reachable nodes. Later they are moved to the home nodes.
Happens before, concurrent
A knows about B, or neither knows about the other.
Siblings
Concurrent values kept by the server until the client merges them.
Version vector
A counter for each replica, used to detect concurrent writes.
Tombstone
A marker that says "this was deleted", kept so that merges do not bring it back.
Part II continues with Chapter 6, Partitioning. It explains how to split data that is too large for one machine, and how to keep the load even across the parts.
7. Check yourself
Eight questions
Choose an answer. You see the explanation at once.
Exercises
Try each exercise before you open the hint. The answers are hidden until you ask for them.
Calculation · exercise 1
Quorum overlap
n = 5 replicas. Which pairs (w, r) guarantee that a read sees the latest acknowledged write? Check (2,2), (3,3), (3,2), and (1,5).
Show hint
The guarantee needs w + r greater than n.
Show answer
(2,2): 4 is not greater than 5, no guarantee. (3,3): 6 > 5, yes. (3,2): 5 is not greater than 5, no guarantee. (1,5): 6 > 5, yes, but every write must reach all five replicas to be acknowledged by one, so writes are slow.
Pen and paper · exercise 2
Which anomaly?
A user posts a comment, reloads, and it is missing because the reload hit a lagging follower. Then a second reload shows it, and a third does not. Name the two guarantees that are missing, and one fix for each.
Show hint
Look at each read on its own, then compare reads with each other.
Show answer
Read-your-writes is missing: fix by reading the user's own recent writes from the leader. Monotonic reads is missing (the comment disappeared between reads): fix by pinning each user to one replica.
Design · exercise 3
Multi-leader conflict rule
Two data centers both accept edits to a product price. Choose a conflict rule for the price, and explain what it loses or keeps.
Show hint
Last-write-wins is simple. Think about whether a discarded price matters.
Show answer
Keep both as siblings and ask a person or a business rule (for example, the lower price). Last-write-wins silently drops one price, which is data loss a shop cannot accept. A deterministic rule that is documented is the minimum.