Concepts

Agreeing under failure

Consistency

Replication

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.

leader-followerfailoverlagdurability

Try it

Move the dials — the sentence under the picture changes.
Replication
Leadercommitted v0writes land hereFollower 0applied v0Follower 1applied v0acknowledged to client: v00 writes on the wire
The leader acknowledges immediately and replicates in the background, so writes are fast and stay up when a follower is down. Followers are 0 writes behind right now. Write a few times, then kill the leader mid-flight.

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.

writeschange logreadsAppLeaderall writesFollower 1reads · 40 ms behindFollower 2reads · 1.2 s behind
Leader–follower: one node takes writes and streams its change log; followers apply it and serve reads — each a little behind.

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".

Synchronous
never lose a write

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.

Asynchronous
the default

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.

Semi-synchronous
usual compromise

Wait for one follower, not all. Bounded loss (zero, if that follower survives) for one machine's worth of availability risk.

Postgres: choosing per transactionSQL
-- 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.

UserLeaderFollowerUPDATE users SET email = 'new@…'OKchange log: email = 'new@…'takes 300 ms to arriverefresh: SELECT email …routed to a follower 50 ms later'old@…'the user's own change is missing
Read-your-writes: the user wrote to the leader and read from a follower that had not caught up.
SymptomNameFix
I saved, refreshed, and my change is goneRead-your-writesSend a user's reads to the leader for a few seconds after they write
I refreshed and saw older data than a moment agoMonotonic readsPin 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 orderConsistent prefixKeep rows that must be read together on the same partition
Read-your-writes with a sticky windowTypeScript
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.

  1. 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.

  2. 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.

  3. 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.