Lessons
1 · System Design Foundations
2 · APIs and Communication
3 · Capacity Estimation
4 · Core Building Blocks
5 · Databases
- 12Relational Databases and Data Modeling for System Design
- 13Database Indexes and Query Performance: How to Make Reads Fast
- 14Transactions, Isolation Levels and Concurrency Control: Preventing Race Conditions
- 15Database Replication: Primary-Replica, Read Replicas, Lag and Failover
- 16Database Sharding and Partitioning: How It Works and When You Need It
- 17SQL vs NoSQL: Data Models and How to Choose the Right Database
6 · Distributed Systems
- 18Why Distributed Systems Are Hard: Partial Failure, Timeouts and Clocks
- 19CAP Theorem and Consistency Models Explained Without the Myths
- 20Idempotency, Retries and Message Delivery Guarantees
- 21Distributed Transactions: Two-Phase Commit, the Outbox Pattern and Sagas
- 22Distributed Locks, Leases, Leader Election and Consensus
7 · Reliability and Operations
8 · Architecture and Security
9 · Interview Method and Foundation Case Studies
10 · Real-World Case Studies
- 33Design a Notification System: Email, SMS and Push at Scale
- 34Design a Chat System Like a Messaging App
- 35Design a News Feed: Fan-Out, Ranking and the Celebrity Problem
- 36Design Search Autocomplete (Typeahead)
- 37Design a Distributed Job Scheduler
- 38Design a Ticket Booking System Without Overselling
- 39Design a Payment System: Idempotency, Ledgers and Reconciliation
11 · Large-Scale Case Studies
- 40Design a Video Streaming Platform: Upload, Transcoding and Adaptive Streaming
- 41Design a Ride-Hailing System: Location, Matching and Real-Time Updates
- 42Design a Food Delivery Platform: Orders, Restaurants and Delivery Partners
- 43Design an E-Commerce System: Catalog, Cart, Checkout, Inventory and Flash Sales
- 44Design a Web Search Engine: Crawling, Inverted Indexes and Ranking
12 · Interview Readiness
Lesson 15 · Databases
Database Replication: Primary-Replica, Read Replicas, Lag and Failover
Why databases keep copies on several machines, and what those copies cost. Covers primary-replica replication, synchronous versus asynchronous replication, read replicas for scaling, replication lag and the read anomalies it causes, read-your-writes routing, failover and split brain, multi-leader and leaderless replication, and why replication is not a backup.
For
Interview candidates building towards SDE-2 depth, and developers whose systems use read replicas or depend on database failover.
Level
Before you start
Read Relational Databases and Data Modeling (article 12) and Transactions and Concurrency Control (article 14). Availability arithmetic from article 02 is used in the failover discussion.
On this page
Key takeaways
- Replication keeps copies of data on several machines for availability, read capacity, durability and locality; it does not add write capacity.
- Asynchronous replication is fast but can lose recently committed writes on failover; synchronous replication protects them at the cost of write latency and availability.
- Replicas lag behind the primary, so reads from them can be stale; route a user's reads to the primary or a caught-up replica right after they write.
- Failover must detect failure carefully, promote the most up-to-date replica, redirect clients and fence the old primary to avoid split brain.
- Replication copies mistakes instantly; you still need backups and point-in-time recovery.
So far Pixly's database is one machine. If it dies, every write fails and, unless the cache is warm, most reads fail too. And even when it is healthy, everything not served by the cache lands on that one machine. Both problems have the same first answer: keep copies of the data on other machines. That is replication.
Replication sounds simple ("just copy the data") but every interesting question in distributed data shows up here first: how up to date is a copy, what happens to writes in flight when a machine fails, and how do clients know which copy to trust. This article answers those questions for the most common setups.
What you will learn
#- Why replicate, and what replication does not solve.
- How primary-replica (leader-follower) replication works.
- Synchronous versus asynchronous replication, and what each risks.
- Read replicas for scaling reads, and their limits.
- Replication lag and the anomalies it causes, with fixes such as read-your-writes routing.
- Failover: detection, promotion, redirection, fencing and split brain.
- Multi-leader and leaderless replication, briefly.
- Why replication is not a backup.
Why replicate
#Goal | How replication helps |
|---|---|
Availability | If the primary fails, a replica can take over |
Read scaling | Spread read queries across several copies |
Durability | A committed write exists on more than one machine |
Locality | A copy near users in another region serves their reads faster |
Isolation of workloads | Run reports, analytics and backups on a replica instead of the primary |
What replication does not do: increase write capacity. Every copy must apply every write. If writes are the bottleneck, you need fewer or smaller writes, or partitioning (article 16).
Primary-replica replication
#The most common setup has one primary (also called leader or master) and one or more replicas (followers, standbys):
- All writes go to the primary.
- The primary records each change in a log (in PostgreSQL, the write-ahead log, or WAL).
- Replicas receive the log and apply the same changes, in the same order.
- Replicas serve reads; they reject writes.
writesClients ----------> PRIMARY ---- change log ----> REPLICA 1 (reads) | \-------> REPLICA 2 (reads) +----------------- reads ---------------------^PostgreSQL's documentation describes this as streaming replication: the standby connects to the primary, which streams WAL records as they are generated, and standbys can serve read-only queries as hot standbys (PostgreSQL: Log-Shipping Standby Servers). Managed services work the same way; AWS describes RDS read replicas as read-only copies to which updates on the primary are copied asynchronously (Working with DB instance read replicas).
Synchronous versus asynchronous replication
#The key question: when does the primary tell the client "committed"?
Asynchronous
#The primary commits locally, replies to the client, and ships the change to replicas afterwards.
- Fast: write latency is unaffected by replicas.
- Available: the primary keeps accepting writes even if every replica is down.
- Risk: if the primary crashes before a change reaches any replica, that committed change is lost on failover.
PostgreSQL's documentation states this directly: streaming replication is asynchronous by default, so if the primary crashes, some committed transactions may not yet have been replicated, causing data loss proportional to the replication delay at the time of failover (PostgreSQL: Log-Shipping Standby Servers).
Synchronous
#The primary waits until at least one replica confirms it has the change before replying "committed".
- Durable: an acknowledged write exists on at least two machines; failover to that replica loses nothing.
- Slower: every commit waits for a network round trip to the replica. Inside one region that is often around a millisecond; across regions it can be 50 to 200 ms or more.
- Availability risk: if the synchronous replica is down or slow, writes stall. Setups therefore usually allow "any one of several replicas" to acknowledge. PostgreSQL, for instance, lets you name several standbys and require acknowledgements by priority (
FIRST) or by quorum (ANY) (PostgreSQL: Log-Shipping Standby Servers).
A common production shape combines both: one synchronous standby in another availability zone (for zero-data-loss failover within the region) plus asynchronous read replicas (for read scaling) plus perhaps an asynchronous replica in another region (for disaster recovery). AWS's RDS documentation describes a similar combination: a synchronous standby for high availability, which does not serve reads, alongside asynchronous read replicas (Working with DB instance read replicas).
Asynchronous | Synchronous | |
|---|---|---|
Write latency | Unchanged | Plus one round trip to the replica |
Data loss on failover | Recent writes (up to the lag) | None, if failing over to the synchronous replica |
Effect of a slow replica | None on writes | Writes slow down or stall |
Typical use | Read replicas, cross-region copies | High-availability standby in the same region |
Read replicas for scaling reads
#Send read queries to replicas and writes to the primary. With two replicas, read capacity roughly triples (primary plus two copies), as long as the reads can tolerate slightly stale data.
How applications route:
- Separate connection pools in the application: one for the primary, one for replicas, chosen per query.
- A database proxy or load balancer that sends reads to replicas.
- Managed reader endpoints that balance across replicas.
Limits:
- Writes are not scaled. And every replica must apply all writes, so a write-heavy system can leave replicas permanently behind.
- Each replica has the full dataset. Replicas do not help if the data does not fit on one machine.
- Stale reads, the subject of the next section.
Replication lag and its anomalies
#Replication lag is how far a replica is behind the primary, in time or in log position. Usually it is small (PostgreSQL's documentation says typically under a second for streaming replication), but it grows during write bursts, long-running queries on the replica, network problems or replica maintenance.
Lag causes visible anomalies. Three you should be able to name:
1. Reading your own write fails
#User edits caption --> primary (committed)User reloads page --> replica (not yet applied) --> sees OLD captionUser: "my edit was lost!" and edits againRead-your-writes consistency means a user always sees their own changes. Ways to provide it:
- Read the user's own data from the primary for a short time after they write (for example 10 seconds, tracked in their session).
- Track the log position of the user's last write and read from a replica only if it has applied that position (otherwise use the primary or wait briefly).
- Route all reads of things the user can edit (their profile, their settings) to the primary, and use replicas for everything else.
2. Going back in time (monotonic reads)
#A user loads a page from replica A (which is up to date) and sees a new comment. They reload, hit replica B (which lags), and the comment disappears. Monotonic reads means a user never sees older data after having seen newer data. A simple fix: pin each user to one replica (for example, by hashing their user id), so their view only moves forward.
3. Effects before causes (causal order)
#Someone posts a question; someone else answers. A third user's reads hit a replica that has the answer but not yet the question. Consistent prefix or causal consistency prevents this. It matters most in partitioned and multi-leader systems (article 19).
Read-your-writes in code
#This Java program simulates a primary, a replication log and a lagging replica. A naive replica read returns the old caption; a read-your-writes check uses the replica only if it has applied the client's last write position. The program is a model of the routing rule; real databases expose the log position through their own functions.
// File: ReplicaLagDemo.javaimport java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class ReplicaLagDemo { record Change(long position, String key, String value) {} static final List<Change> log = new ArrayList<>(); // the primary's change log static final Map<String, String> primary = new HashMap<>(); static final Map<String, String> replica = new HashMap<>(); static long replicaApplied = 0; // last log position applied static long write(String key, String value) { primary.put(key, value); long position = log.size() + 1; log.add(new Change(position, key, value)); return position; // returned to the client } static void replicate(int changes) { // the replica catches up gradually for (int i = 0; i < changes && replicaApplied < log.size(); i++) { Change c = log.get((int) replicaApplied); replica.put(c.key(), c.value()); replicaApplied = c.position(); } } static String readYourWrites(String key, long clientLastWrite) { if (replicaApplied >= clientLastWrite) { return replica.get(key) + " (from replica)"; } return primary.get(key) + " (from primary: replica is behind)"; } public static void main(String[] args) { write("caption:9001", "Sunset"); replicate(1); long myWrite = write("caption:9001", "Sunset at Marina Beach"); System.out.println("Naive replica read: " + replica.get("caption:9001")); System.out.println("Read-your-writes: " + readYourWrites("caption:9001", myWrite)); replicate(1); System.out.println("After catching up: " + readYourWrites("caption:9001", myWrite)); System.out.println("Lag in log positions: " + (log.size() - replicaApplied)); }}Naive replica read: SunsetRead-your-writes: Sunset at Marina Beach (from primary: replica is behind)After catching up: Sunset at Marina Beach (from replica)Lag in log positions: 0Failover
#When the primary fails, a replica must become the new primary. This is failover, and it is harder than it sounds. It has four steps:
- Detect that the primary has failed. Usually by missed heartbeats over a timeout. Too short a timeout causes unnecessary failovers on a brief network blip (each costing seconds of unavailability and possibly data); too long means minutes of downtime.
- Choose the new primary: the replica with the most recent data (the furthest log position), so the least is lost.
- Redirect clients: update DNS, a virtual IP, a proxy's configuration or a service registry so writes go to the new primary.
- Fence the old primary: make sure it can no longer accept writes if it comes back, for example by revoking its access or shutting it down.
Split brain
#If the old primary was not really dead (only cut off from the failure detector by a network partition), and nobody fenced it, you now have two primaries both accepting writes. Their data diverges, and merging it afterwards is painful or impossible. This is split brain, and it is the most dangerous failover failure.
Protections:
- Fencing (step 4), so a deposed primary cannot write.
- Majority-based decisions: the failover manager uses a consensus system (article 22) so that only a group holding a majority of votes can promote a primary; a minority side of a partition cannot.
- Fencing tokens on downstream writes, so a stale primary's writes are rejected (article 22).
What failover costs
#- Downtime: detection time plus promotion plus redirection, typically seconds to a minute or two for well-configured systems.
- Data loss with asynchronous replication: everything committed on the old primary but not yet replicated. At Pixly's 1,800 writes per second and 2 seconds of lag, up to about 3,600 committed writes could vanish. That is why important data uses a synchronous standby.
- Connection storms: every application reconnects at once to the new primary (connection pooling and backoff help).
Managed databases automate most of this, but you should still be able to explain it, test it and know its data-loss window.
Other replication topologies
#Multi-leader
#Several nodes accept writes (often one per region) and replicate to each other. Users in each region write locally, with low latency, and each region keeps working if another is cut off.
The cost is write conflicts: two regions change the same row at the same time. Resolution strategies include last write wins by timestamp (simple, but silently discards one write and depends on clocks), application-specific merges, and data types designed to merge automatically (conflict-free replicated data types, or CRDTs). Use multi-leader only when local writes in several regions are a real requirement, and design data so conflicts are rare (for example, each user's data is "owned" by one region).
Leaderless (quorum)
#Any of N replicas accepts reads and writes. A client writes to several replicas and considers the write successful when W acknowledge; it reads from R replicas and takes the newest value. If W + R > N, every read overlaps at least one replica with the latest write. Amazon's Dynamo paper describes this design, along with techniques such as hinted handoff and anti-entropy repair, and it inspired systems such as Apache Cassandra (Dynamo: Amazon's Highly Available Key-value Store). Article 19 works through the quorum arithmetic.
Topology | Writes accepted at | Strength | Main cost |
|---|---|---|---|
Primary-replica | One primary | Simple; no write conflicts | Failover; writes limited to one node |
Multi-leader | Several leaders | Local writes in several regions; tolerates region isolation | Conflict resolution |
Leaderless | Any replica | No failover step; tunable consistency per request | Complex reasoning; stale reads possible; repair needed |
Replication is not a backup
#Replication copies every change, including the bad ones. If someone runs DELETE FROM photos by mistake, or a bug corrupts rows, every replica faithfully applies it within a second. To recover you need backups, ideally with point-in-time recovery: periodic full backups plus the archived change log, so you can restore the database to the moment just before the mistake. PostgreSQL documents this as continuous archiving and point-in-time recovery (PostgreSQL: Continuous Archiving and Point-in-Time Recovery). Test restores regularly; an untested backup is a hope, not a plan. Article 24 connects this to recovery objectives.
Worked example: Pixly's replication
# Region: primary (3 availability zones) App servers --writes--> PRIMARY (zone A) | |-- synchronous --> STANDBY (zone B) failover target, no reads | |-- async --------> READ REPLICA 1 (zone B) | |-- async --------> READ REPLICA 2 (zone C) | `-- async --------> DR REPLICA (another region) `--reads--> reader endpoint (replicas 1 and 2) Backups: nightly full + continuous log archive to object storageRead routing rules:
Read | Where | Why |
|---|---|---|
Feed, other users' photos and profiles | Replicas (after cache misses) | Staleness of a second is fine |
The user's own profile and photos within 10 s of a write | Primary | Read-your-writes |
Anything used to make a decision (has this user already liked? account status for login) | Primary | Correctness |
Analytics and exports | A dedicated replica, never the primary | Workload isolation |
Failure walk-through:
- Primary fails: the managed failover promotes the synchronous standby within about a minute; no committed writes are lost; clients reconnect through the same endpoint name.
- A read replica fails: the reader endpoint stops sending it traffic; the other replica and the cache absorb the reads.
- Replica lag spikes during a bulk import: lag is monitored, and replicas lagging more than a threshold are removed from the reader pool until they catch up.
- Bad migration deletes data: restore from the continuous archive to a point before the migration, into a new instance, and copy back the affected rows.
Failure modes
#Failure | Effect | Mitigation |
|---|---|---|
Lag spike | Stale reads; users think writes were lost | Monitor lag; read-your-writes routing; remove lagging replicas from rotation |
Primary crash with async replication | Recent committed writes lost | Synchronous standby for critical data; understand the window |
False failure detection | Unneeded failover, brief outage | Sensible timeouts; multiple observers |
Split brain | Two primaries, divergent data | Fencing, majority-based promotion, fencing tokens |
Synchronous replica slow or down | Writes stall | Quorum of several standbys; fall back carefully |
Replicated mistake or corruption | All copies wrong | Backups and point-in-time recovery |
Too many replicas | Primary spends effort shipping logs; more lag | A few replicas plus caching; cascading replicas if supported |
Trade-offs
#Decision | You gain | You pay |
|---|---|---|
Add read replicas | Read capacity, workload isolation | Stale reads, routing logic, cost |
Synchronous replication | No data loss on failover | Write latency; possible write stalls |
Asynchronous replication | Fast writes, simple | Data-loss window on failover |
Automatic failover | Short downtime without humans | Risk of false failovers and split brain if done badly |
Multi-leader across regions | Local writes, regional independence | Conflicts and their resolution |
Common mistakes
#- Expecting replicas to scale writes.
- Sending a user's read straight after their write to a lagging replica.
- Using asynchronous replication for data that must never be lost, without knowing the loss window.
- Ignoring split brain in a failover design.
- Treating replicas as backups.
- Running heavy analytics on the replica that is also the failover target.
In an interview
#- Add replication with a reason: availability (standby), read scaling (replicas), or locality (another region).
- Say whether it is synchronous or asynchronous and what that means for data loss and latency.
- Mention lag and how you handle read-your-writes for the user who just wrote.
- If asked about failover, name the four steps and split brain.
- Say that backups with point-in-time recovery exist separately.
Exercises
#Exercise 1
Route the reads
#An e-commerce site has a primary and three async read replicas. Decide where each read goes and why:
- Product listing pages.
- "My orders" immediately after placing an order.
- Checking stock during checkout.
- A daily sales report.
- A user's saved addresses on the checkout page.
Exercise 2: How much could be lost?
#A primary handles 2,500 writes per second with asynchronous replication. Average lag is 300 ms, but during nightly imports it reaches 8 seconds. The primary crashes during an import, and the most up-to-date replica is promoted. Estimate the worst-case number of lost committed writes, and propose two changes.
Exercise 3: The vanishing comment
#Users report: "I post a comment, the page refreshes, and my comment is not there. If I refresh again, it appears." Explain the cause, and give two fixes with their trade-offs.
Exercise 4: Synchronous across regions?
#A team wants zero data loss even if an entire region fails, so they propose synchronous replication from the primary in India to a replica in Europe, with about 150 ms round-trip time. What happens to write latency and throughput of sequential writes from one client, and what could they do instead?
Show solutionHide solution
- Replicas (behind a cache). Slightly stale product data is fine; final checks happen at checkout.
- Primary (or a replica that has applied the order's write position). The user must see the order they just placed; otherwise they may order again.
- Primary, inside the order transaction with a conditional update (article 14). Stock decisions must use current data.
- A dedicated replica or an analytics store, so the report never competes with live traffic.
- Primary if the user may have just added an address; otherwise a replica with read-your-writes tracking. Showing an address list without the one they just added is confusing at the worst moment (checkout).
Exercise 2
Show solutionHide solution
Worst case, everything committed during the lag window is lost: 2,500 writes per second x 8 seconds = about 20,000 committed writes. (At the normal 300 ms lag it would be about 750.)
Changes:
- Add a synchronous standby in another zone for failover, so committed writes always exist on two machines. Keep async replicas for reads.
- Throttle or reschedule the import so it does not create large lag, for example by batching with pauses, or importing during the quietest period; alert when lag exceeds a threshold.
- Also: make the import idempotent and restartable, so lost import writes can be replayed safely after failover.
Exercise 3
Show solutionHide solution
The comment is written to the primary, but the page reload reads from a lagging read replica that has not yet applied it. The second refresh hits a replica (or the same one, later) that has caught up. It is a read-your-writes violation; if different refreshes hit different replicas, users may also see comments appear and disappear (a monotonic-reads violation).
Fixes:
- After a user writes, read their view of that page from the primary for a few seconds (track the time of their last write in the session). Simple; adds some primary load.
- Track the log position of the user's last write and only use replicas that have applied it, waiting briefly or falling back to the primary otherwise. Precise; needs database support and more logic.
- Optimistic UI: the client shows the posted comment immediately from its own state. Good experience, but other devices of the same user can still see the stale view, so combine it with one of the above.
Exercise 4
Show solutionHide solution
Every commit would wait for the 150 ms round trip to Europe. A single client issuing writes one after another could commit at most about 1 / 0.15 = about 6 to 7 writes per second, and every user-facing write would get at least 150 ms slower. Overall throughput can still be high with many concurrent clients, but latency and lock hold times grow, and any network trouble between regions stalls writes in India.
Alternatives:
- Synchronous replication within the region (across zones, about a millisecond away) for zero loss on single-zone failures, plus asynchronous cross-region replication for disaster recovery, accepting a small data-loss window for the rare full-region disaster (article 24 calls this the recovery point objective).
- If cross-region zero loss is truly required for a small subset of data (for example, payment records), make only those writes synchronous across regions, or use a database designed for multi-region consensus, and accept the latency for that subset.
Where to go next
#- Next: Database Sharding and Partitioning: How It Works and When You Need It, for when the data or the writes no longer fit on one primary.
- Later: consistency models and quorums (article 19), leader election and fencing (article 22), and recovery objectives (article 24).
Sources & further reading
- Technology
- Software Engineering
- #availability
- #consistency
- #databases
- #distributed systems
- #replication
- #roadmap
- #scalability
- #system design
- #system design interview
Connected lessons
Linked from 3 guides
Other pages in the library that point here.
Keep reading
More in Technology →Guide · Technology
Start Here: Your Roadmap from Zero to Job-Ready DSA
Guide · Technology
SQL and PostgreSQL Fundamentals for Java Developers
Guide · Career
A LinkedIn Profile That Gets Recruiter Messages

