Agreeing under failure
ConsistencyReplication
Keeping more than one copy of the data, and what a failover costs when the copies disagree.
Synchronous replication charges every write; asynchronous replication charges you once, during a failure.
Try it
Move the dials — the sentence under the picture changes.In plain words
Replication keeps more than one copy of your data, on more than one machine. It buys three things: durability (a disk dying does not lose the data), read capacity (several copies can answer reads), and staying up when a machine goes away. The cost is that copies can disagree, and every replication design is an answer to when they are allowed to.
Leader and followers
One node — the leader (or primary) — accepts all writes and streams its change log to the followers, which apply it in the same order. Reads can go anywhere. This is the shape of Postgres, MySQL, Redis and most managed databases.
The one decision that matters is whether the leader waits for followers before telling the client "done".
The leader does not acknowledge until a follower has the write. A failover loses nothing. Every write pays a round trip to the slowest follower, and if a follower is down, writes stop. Almost nobody runs this fully.
The leader acknowledges at once and ships the change in the background. Fast, and stays up when a follower is sick. But anything in flight when the leader dies is gone — and the client was told it was saved. The widget's punchline: kill the leader mid-write and count what vanished.
Wait for one follower, not all. Bounded loss (zero, if that follower survives) for one machine's worth of availability risk.
-- Default: async. Acknowledge as soon as the leader has it on disk.
SET synchronous_commit = local;
-- For this one transaction (a payment), wait for a standby to have it too.
BEGIN;
SET LOCAL synchronous_commit = on; -- with synchronous_standby_names set
INSERT INTO payments (order_id, amount) VALUES (42, 50.00);
COMMIT;Replication lag, and the bugs that look like the database lying
Followers are behind by an amount that varies with load: milliseconds usually, seconds under a heavy write burst. This produces a family of bugs that are really routing bugs.
| Symptom | Name | Fix |
|---|---|---|
| I saved, refreshed, and my change is gone | Read-your-writes | Send a user's reads to the leader for a few seconds after they write |
| I refreshed and saw older data than a moment ago | Monotonic reads | Pin a session to one follower, or track a "last seen" position and only read from followers past it |
| Two related rows appear in the wrong order | Consistent prefix | Keep rows that must be read together on the same partition |
async function query(userId: string, sql: string) {
const lastWrite = await redis.get(`last-write:${userId}`); // set on every write
const recent = lastWrite && Date.now() - Number(lastWrite) < ;
const conn = recent ? leader : pickFollower(); // 5 s of leader reads after a write
return conn.query(sql);
}Failover
The leader dies. Someone has to notice, choose a new leader, and redirect writes. Every step has a failure mode.
- Detect
A heartbeat stops. But a slow leader and a dead one look identical from outside — wait too little and you fail over on a GC pause; wait too long and writes are down for a minute.
- Elect
Pick the follower with the most of the log. Needs a majority to agree (see consensus) or two followers may each think they won.
- Redirect and fence
Point clients at the new leader — and make sure the old one, if it was only slow, cannot keep accepting writes when it wakes up.
Other shapes
- Multi-leader. A writable node in each region: fast local writes, and write conflicts become routine rather than an emergency. Needs a merge rule for every table.
- Leaderless (Dynamo, Cassandra). Every write goes to N nodes and waits for W of them; every read asks R. No failover because there was no leader; consistency becomes a dial per request. The key-value store problem builds one.
Take this with you
- The one idea: copies can disagree. Every replication setup is a decision about when that is allowed and what a reader is promised.
- In an interview, say leader-follower, async by default, and name the two lag bugs (read-your-writes, monotonic reads) and how routing fixes them.
- At work, find out how far behind your replicas run at peak, and whether anything reads its own write from a follower.