Learn why we copy data to several machines, how leader-follower, multi-leader and leaderless replication work, and how lag, failover and split-brain cause trouble.
What you'll learn: By the end of this lesson you will be able to choose between leader-follower, multi-leader and leaderless replication for a given workload. You will explain synchronous versus asynchronous replication and what each costs. You will describe replication lag and fix a read-your-writes bug. You will explain failover and why split-brain is dangerous.
Imagine a library with one copy of a popular book. Only one person can read it at a time, and if it is lost in a fire, it is gone. Now the library buys three copies and puts them in different buildings. More people can read at once, readers pick the nearest building, and one fire no longer erases the book.
But a new problem appears. When the author publishes a corrected edition, someone has to update all three copies. For a while, different buildings hold different versions. Replication in databases is exactly this: keeping copies of the same data on several machines, and dealing with the fact that the copies cannot all change at the same instant.
The core idea
Replication means storing the same data on multiple nodes and keeping those copies in sync. A node is one machine running the database. We replicate for three reasons:
Availability. If one node dies, another has the data and can take over.
Read scale. Many nodes can answer read queries, so read capacity grows with the number of copies.
Locality. A copy near the user, say in another continent, answers faster than a copy far away.
Notice what replication does not do. It does not increase the amount of data you can store, because every node holds the full dataset. That is the job of sharding. It also does not protect you against a bad delete, because the delete is replicated too. For that you need backups, as covered in System Design: Reliability Basics.
The central difficulty is simple to state: a write must reach several machines, and machines and networks fail and slow down. Every design below is a different answer to the question "who accepts writes, and when is a write considered done?"
Leader-follower replication
This is the most common design, used by PostgreSQL, MySQL and many other databases. One node is the leader (also called primary or master). All writes go to it. The other nodes are followers (replicas, secondaries). The leader sends each change to the followers, usually as a stream of changes it also writes to its own log. Followers apply the changes in the same order. Reads can be served by the leader or by any follower.
Because only one node accepts writes, there are no write conflicts. The order of changes is decided in one place. That simplicity is why this design is the default choice.
How the change stream is shipped varies. Many databases ship the write-ahead log (the low-level record of every change) or logical row changes; replaying SQL statements is fragile with non-deterministic functions such as the current time. The PostgreSQL documentation at postgresql.org/docs describes its streaming replication in detail.
Synchronous versus asynchronous
When the leader receives a write, when should it tell the client "done"?
Synchronous: the leader waits until the follower has confirmed it stored the change. If the leader then dies, that follower has the write. The cost is latency, and a stuck follower can block writes.
Asynchronous: the leader confirms to the client immediately and ships the change in the background. Writes are fast and a slow follower does not slow anyone down. The cost is that if the leader dies before the change reaches a follower, that write is lost after failover.
Semi-synchronous: one follower is synchronous and the rest are asynchronous. If the synchronous follower becomes slow or fails, another is promoted into that role. At any moment at least two nodes have every acknowledged write, without making every write wait for every follower.
Mode
Write latency
Data loss on leader crash
When to use
Alternative
Asynchronous
Lowest
Recent writes may be lost
Read-heavy apps that tolerate small loss; cross-region copies
Semi-synchronous
Semi-synchronous
Moderate
Acknowledged writes survive a single failure
Databases that must not lose acknowledged writes
Fully synchronous
Fully synchronous
Highest; blocks if a follower stalls
None, if all followers confirm
Small clusters with strict durability needs
Consensus-based systems
NOTE
Fully synchronous replication to every follower is rarely used, because one slow or dead follower would halt all writes. Systems that need both durability and availability usually use a majority quorum instead, as in the leaderless section below or a consensus protocol (Advanced: Consensus and Leader Election).
Replication lag and the bugs it causes
With asynchronous replication, followers are slightly behind the leader. The delay is called replication lag. It is often milliseconds but can grow to seconds or minutes under heavy load, after a network problem, or while a follower catches up. Reading from a follower means reading data that is a little old. This is eventual consistency: if writes stop, all copies will eventually agree. Three classic anomalies follow, each with a fix.
Read-your-writes
A user places an order. The write goes to the leader. The page reloads, the read goes to a lagging follower, and the order is missing. The user thinks it failed and orders again.
sequenceDiagram
participant U as User
participant L as Leader
participant F as Follower
U->>L: place order
L-->>U: ok
Note over L,F: replication still in flight
U->>F: read order list
F-->>U: order missing
L->>F: apply order
U->>F: read order list again
F-->>U: order now visible
Fixes:
Read from the leader for data the user has just changed, for example for a short window after their write.
Track the position (log sequence number or timestamp) of the user's last write, and only read from a follower that has caught up to it.
Route a user's requests consistently to the same replica. This does not guarantee they see their write, but it keeps their view from going backwards while that replica stays up.
Monotonic reads
A user refreshes twice. The first read hits a fresh follower and shows a new order; the second hits a stale one and the order vanishes. Time seems to move backwards. Pinning each user to one replica prevents it while that replica stays available.
Consistent prefix reads
Two writes happen in order: a question, then its answer. A reader sees the answer without the question, because the writes replicated through different paths. This matters mostly in partitioned systems, where partitions replicate independently. The fix is to send causally related writes through the same partition or use a system that tracks causality.
When the leader fails, the system must pick a new one. This is failover. It has several steps, and every step can go wrong:
Detect the failure. Usually by missed heartbeats (regular "I'm alive" messages). Too short a timeout causes false alarms; too long means long downtime.
Choose a new leader. Typically the follower with the most up-to-date data.
Reconfigure. Tell clients and the other followers about the new leader.
Handle the old leader. If it comes back, it must realise it is no longer in charge and become a follower.
Lost writes. With asynchronous replication, the new leader may be missing the last few writes of the old one. If the old leader returns with them, they conflict or are discarded. Discarding acknowledged writes can do real harm: if the new leader reuses an auto-incrementing ID already handed to another system, data from two users can get mixed up.
Split-brain. Two nodes both believe they are the leader and both accept writes. The copies diverge and merging them may be impossible. This can happen when a network partition makes the old leader look dead while it is actually alive.
Wrong timeouts. A slow but healthy leader gets replaced during a load spike, and the failover itself adds more load.
Defences against split-brain include: requiring a majority of nodes to agree on the leader (a quorum, so two groups cannot both reach majority), using leases (a leader's authority expires unless renewed), and fencing (the storage or followers reject requests from an old leader using an increasing token). Tools such as etcd and ZooKeeper exist largely to provide this agreement reliably.
WARNING
Automatic failover is a feature you must test, not assume. Many teams discover its edge cases in production. Rehearse failover in a staging environment and measure how long it takes and what it loses.
Multi-leader replication
In multi-leader (or multi-primary) replication, several nodes accept writes, and each forwards its changes to the others. The usual reason is geography: a leader in each of Asia, Europe and the Americas lets users write locally, and a regional outage does not stop the other regions. Offline-capable apps, such as a calendar syncing between phone and laptop, are another example: every device is effectively a leader.
The price is write conflicts. Two users edit the same record in different regions at the same moment, both writes are accepted locally, and the system must decide the result:
Last write wins (LWW): keep the later timestamp. Simple, but it silently throws away the other write, and clock differences make "later" unreliable.
Merge: combine the changes, as collaborative editors and conflict-free replicated data types (CRDTs) do.
Application resolution: store both versions and let the application or the user decide.
Avoid conflicts: route all writes for a record to one "home" region, which removes most conflicts by design.
Uniqueness constraints and auto-increment IDs do not work across leaders without extra care. Use multi-leader only when you truly need local writes in several places or offline operation.
Leaderless replication and quorums
In leaderless designs, such as Dynamo-style systems like Cassandra, no node is special. A client (or a coordinator node) sends each write to several replicas and reads from several replicas.
Let N be the number of replicas holding a piece of data, W the number that must acknowledge a write, and R the number that must answer a read. If R + W > N, every read set overlaps every write set in at least one node, so a read will include at least one replica that saw the latest successful write.
For example, with N = 3, W = 2 and R = 2: a write succeeds when two of three replicas confirm, a read asks two of three, and at least one node in the read has the newest value, which the client picks by version. You can tune the numbers: W = 1 and R = 3 favours fast writes, W = 3 and R = 1 favours fast reads, and each reduces availability for the expensive operation.
Two cautions keep this honest:
Overlap alone does not give the strict guarantee of a single leader. Concurrent writes, sloppy quorums (writing to other nodes temporarily when the usual ones are unreachable), partial write failures and clock-based conflict resolution can all produce stale or lost values. Treat quorums as "better odds", not as a transaction.
Replicas that missed writes are repaired by read repair (fixing stale copies when a read notices a mismatch) and background anti-entropy processes.
Choosing a replication design
Design
Strength
Cost
Use when
Alternative
Leader-follower
Simple, no write conflicts, strong tooling
One write node; lag on followers; failover is delicate
Most applications, especially read-heavy ones
Add caching; shard if writes outgrow one node
Multi-leader
Local writes in many regions; works offline
Conflict resolution; weak constraints
Multi-region writes, offline sync
Single leader plus read replicas near users
Leaderless (quorum)
No failover step; tolerates node loss smoothly
Tuning, stale reads, conflict handling
Very high availability, large-scale key-value workloads
Leader-follower with a consensus layer
The same choice as a decision flow:
flowchart TD
S["Choosing a replication design"] --> Q1{"Must writes be accepted in several regions or offline?"}
Q1 -->|yes| Q2{"Can each record be routed to one home region?"}
Q2 -->|yes| R1["Leader-follower per region with home-region routing"]
Q2 -->|no| R2["Multi-leader with an explicit conflict policy"]
Q1 -->|no| Q3{"Need no failover step and can tolerate stale reads?"}
Q3 -->|yes| R3["Leaderless quorum store"]
Q3 -->|no| R4["Leader-follower, semi-synchronous"]
Most teams land on the bottom right, and the diagram shows why: the other exits each require a stated need. A sensible start for most products is one leader with two or three followers in different availability zones, semi-synchronous replication, non-critical reads (reports, catalogues) served by followers, and "the thing I just changed" served by the leader or a caught-up follower. Consider multi-region writes only if latency or regulations demand them.
In practice: moving reports to read replicas, then "my order disappeared"
NOTE
A realistic scenario, not a case history. This is a composite example built from common production patterns. It does not describe any specific company, and every number in it is an illustrative assumption.
The situation
A B2B ordering SaaS serves 2,000 wholesale customers, who place orders through a web app and read monthly sales reports. A team of nine runs a Spring Boot application on Kubernetes against a managed PostgreSQL primary. Month-end report runs are heavy aggregate queries, and at 09:00 on the first working day the primary hits 90% CPU and order placement slows from about 200 ms to over 2 seconds (illustrative). The team adds a read replica and sends reports to it. It works, so someone flips a framework setting to send every GET to the replica.
Within a week support logs "my order disappeared" tickets. A customer places an order, is redirected to the order list, and sees nothing, so some place it again. Assume duplicate orders reach about 0.5% of orders on busy days. Replica lag is normally under a second but rises to 20 seconds or more while the report queries run.
Starting architecture
The replica that serves customers is also the one running multi-minute report queries, so reads and reports share a lag problem.
Options considered
Option
What it fixes
What it costs
Risk
A. Smaller change: reports only go to the replica, all application reads return to the primary
The disappearing orders, at once
A config change
Primary read load comes back, though without the report spike
B. A plus read-your-writes routing: after a write, a session reads from the primary for a short window or until a replica has replayed its write position
Keeps most reads off the primary without the bug
One to two weeks of routing code
Subtle edge cases; a fallback can overload the primary
C. Move reporting to a warehouse fed by nightly extracts
Removes reports from OLTP entirely
Six or more weeks, a pipeline to own
Reports are a day old
The decision
Context
Reports are heavy but infrequent; order pages need to be correct immediately after a write
Decision
Option A as a same-day hotfix, then B for the order list and detail pages. Reports get a dedicated replica, separate from the failover standby
Consequences, good
The bug stops; the primary is protected from report queries; lag on the report replica no longer matters to customers
Consequences, bad
More replicas to run; routing logic in the application; a few reads go to the primary on purpose
Revisit when
Reports keep the report replica above about 70% CPU, or customers need reports fresher than a replica can safely give, so a warehouse becomes worth it
Rollout and verification
Ship the routing as a small decision made once per request:
Read routing decision per requestIncoming request to Is it a write?; Is it a write? to Wrote in the last 10 s? (no); Wrote in the last 10 s? to Replica lag under 5 s? (no); Is it a write? to Primary (yes); Wrote in the last 10 s? to Primary (yes); Replica lag under 5 s? to Primary (no); Replica lag under 5 s? to Replica (yes)Incoming requestIncomingrequestIs it a write?Is it a write?Wrote in the last 10 s?: same sessionWrote in thelast 10 s?same sessionReplica lag under 5 s?Replica lagunder 5 s?Primary: capped fallbackPrimarycapped fallbackReplicaReplicanonoyesyesnoyes
Release it behind a flag for 10% of sessions first. Before that, replay a recorded month-end load against staging with reports running, and check that lag alarms fire. Dashboards that prove it: replica lag (replay_lag from pg_stat_replication on the primary), the percentage of reads routed to the primary and why, report duration, primary CPU, and the rate of repeated order submissions per customer, which is the user-visible symptom. A target of zero "disappeared order" tickets over two month-ends is the real test.
The 2 a.m. failure
At month end, the page reads "Replica lag above 30 s" and soon after "Primary CPU above 90%". A long report is delaying replay on the replica (on a PostgreSQL standby, replay waits for conflicting queries up to a configured limit, which had been raised for reports), the lag guard sends reads to the primary, and the primary becomes the next bottleneck.
sequenceDiagram
participant A as App
participant R as Replica
participant P as Primary
A->>R: long report query
Note over R: replay delayed, lag grows
A->>P: reads rerouted, lag over 5 s
Note over P: CPU saturates
A->>P: order writes slow down
Note over R: operator cancels the report, lag drains
First three checks: on the primary, SELECT client_addr, state, replay_lag FROM pg_stat_replication;; on the replica, SELECT pid, now() - query_start AS age, left(query, 60) FROM pg_stat_activity WHERE state = 'active' ORDER BY age DESC LIMIT 5;; and the dashboard panel showing the share of reads routed to the primary. Mitigation: cancel the offending report with pg_cancel_backend(pid), confirm lag drains, and pause scheduled report generation until traffic calms. Follow-up: a statement timeout on report connections, reports on their own replica (as decided), a cap on how much fallback traffic the primary accepts, and report schedules moved away from the 09:00 order peak.
Architect's notes
Measure lag, not just whether the replica is up. Alert on replay lag in seconds and on the oldest long-running query on each replica.
Ask in the review: "Which reads must see the user's own write?" List them. The answer is usually shorter than people fear.
Do not route by HTTP method alone. A GET right after a POST is the classic trap, so write the exceptions into the design.
Separate the failover replica from the reporting replica. A standby that analysts can saturate is not a standby.
Fallbacks need their own limits. A guard that sends all reads to the primary moves the outage rather than preventing it.
Defer multi-region writes. Cross-region read replicas answer most locality needs at a fraction of the conflict risk.
Common mistakes
Treating replicas as backups. Deletes and corruption replicate instantly. Keep independent, point-in-time backups and test restores.
Reading from followers without handling lag. Users see their own changes vanish. Use read-your-writes routing or read from the leader for fresh data.
Assuming asynchronous replication loses nothing. Acknowledged writes can disappear on failover. Decide your acceptable loss (your RPO) and choose semi-synchronous replication if it is near zero.
Never rehearsing failover. Untested failover breaks in surprising ways. Run drills and time them.
Replicating but putting all copies in one zone. One power or network failure still takes everything down. Spread nodes across availability zones.
Adopting multi-leader to "scale writes". It adds conflicts without increasing total write capacity for a single record. If writes outgrow a node, partition the data instead.
Using last-write-wins casually. It drops data silently, and clock skew picks the wrong winner. Choose conflict handling on purpose.
Key takeaways
Replication copies data for availability, read scale and locality. It does not add storage capacity and it is not a backup.
Leader-follower is the default. One write node means no conflicts and a clear order of changes.
Synchronous trades latency for durability. Asynchronous trades possible data loss for speed; semi-synchronous sits in between.
Lag creates visible bugs. Read-your-writes, monotonic reads and consistent prefix are the guarantees users notice.
Failover is the risky moment. Detection, election, reconfiguration and old-leader handling can each fail.
Split-brain needs majority, leases or fencing. Never rely on timeouts alone to decide who is leader.
Multi-leader means conflicts. Prefer routing writes to one home region unless you truly need otherwise.
Quorums improve odds, not certainty. R + W > N creates overlap, but sloppy quorums and concurrency still allow anomalies.
Practice exercises
Exercise 1 — Starter (30 min): A leader-follower database has one leader and two followers. For each of three modes (asynchronous, semi-synchronous, fully synchronous), write down what a client sees when the leader crashes immediately after acknowledging a write, and whether that write survives. Present it as a table.
Exercise 2 — Intermediate (2 hours): Design the read path for the photo app's profile page. List the five pieces of data on the page (own bio, photo grid, follower count, other users' recent comments, notification badge). For each, decide whether it may be read from a lagging follower, must be read from the leader, or needs a caught-up follower. Explain how your application would implement read-your-writes using a stored write position.
Exercise 3 — Advanced (half day): A leaderless store uses N = 5. Compute, for W and R from 1 to 5, which combinations satisfy R + W > N, and how many node failures each tolerates for reads and for writes. Then describe one concrete scenario (sloppy quorum or concurrent writes) where even a combination satisfying R + W > N returns a stale value, and propose a detection or repair mechanism.
PostgreSQL documentation — reference for streaming replication and failover behaviour in one widely used database.
Enroll to keep reading
Lesson 2 of 14 · System Design Building Blocks: Data, Messaging and Scale
Learn why we copy data to several machines, how leader-follower, multi-leader and leaderless replication work, and how lag, failover and split-brain cause trouble.
In the rest of this lesson
Failover and split-brain
Multi-leader replication
Leaderless replication and quorums
Choosing a replication design
In practice: moving reports to read replicas, then "my order disappeared"
Architect's notes
Enrolling is free. It unlocks every lesson in System Design Building Blocks: Data, Messaging and Scale, tracks your progress across devices and keeps your quiz scores. The newsletter is optional.
Real architecture decisions, LLMOps patterns that survive production, and engineering leadership advice — from 12+ years of building at enterprise scale. Free. No spam. Unsubscribe anytime.
Get new articles by email
Free. We email a confirmation link first, and you can unsubscribe from any email.