Replication and Replication Lag
What Replication Is
Replication means keeping copies of the same database on several servers. One server, the primary, accepts all writes. The other servers, the replicas, copy every change from the primary and can serve reads.
Think of a teacher and photocopies. The teacher writes the notes once (primary). Copies go to several assistants (replicas), so many students can read at the same time. If the teacher is absent, one assistant can take over.
1 writes2App ─────────────────────────→ [ Primary ]3 │ │4 │ copies every change (WAL / oplog)5 │ ┌─────────────┼─────────────┐6 │ ↓ ↓ ↓7 └──── reads ────→ [ Replica 1 ] [ Replica 2 ] [ Replica 3 ]App servers can scale out by just adding copies, because they don't hold data. A database does hold data, so every copy must receive every change. That copying is what replication handles.
How the Copying Works
Every change on the primary is first written to a log, then sent to replicas, which replay it in the same order.
| PostgreSQL | MongoDB | |
|---|---|---|
| Log that gets copied | WAL (write-ahead log) | Oplog (operations log) |
| Replica name | Standby / read replica | Secondary |
| Group name | Primary + standbys | Replica set |
| Automatic failover | Needs a tool (like Patroni) or a managed service | Built in: replicas elect a new primary |
Why Use It
| Benefit | Food app example |
|---|---|
| High availability: a replica takes over if the primary dies | Primary crashes at 8 PM; a replica becomes primary in seconds and orders keep flowing |
| Read scaling: replicas share the read traffic | Menu browsing (many reads) goes to replicas; placing orders (writes) goes to the primary |
| Backups and reports: heavy queries run without slowing the primary | Daily revenue reports run on a replica |
Replication scales reads, not writes. Every replica still has to apply every write. Splitting writes needs sharding, covered later.
Sync vs Async Replication
The key question: when the app writes, does the primary wait for replicas before saying "done"?
1Async: App → Primary writes → "done" to app → replicas copy a moment later2Sync: App → Primary writes → waits for replica to confirm → "done" to app| Asynchronous | Synchronous | |
|---|---|---|
| Write speed | Fast | Slower, waits for a replica |
| If primary crashes | Last few writes may be lost | No committed write is lost |
| Default | Yes, in both PostgreSQL and MongoDB | Must be configured |
| Choose for | Most data | Data you can't lose, like payments |
In MongoDB, a write concern of w: "majority" makes the write wait until most replica set members have it. PostgreSQL uses synchronous_standby_names for the same idea.
Replication Lag
With async replication, replicas are always slightly behind the primary. This delay is replication lag. Usually it's milliseconds, but it can grow to seconds under heavy write load or a slow network.
That causes a classic bug:
1t=0 ms Riya updates her delivery address → write goes to PRIMARY2t=5 ms App reloads her profile → read goes to REPLICA3 Replica hasn't received the change yet4 → shows the OLD address5 → Riya thinks the save failed and edits againSeeing your own change disappear is the problem. The fix is called read-your-own-writes: after a user changes something, make sure they read it from a place that has the change.
| Fix | How it works | Trade-off |
|---|---|---|
| Read own data from primary | Profile, wallet, and "My Orders" always read from the primary | More load on the primary |
| Primary for a short window | After a user writes, send their reads to the primary for a few seconds | Needs tracking per user |
| Majority write + read (MongoDB) | Write with w: "majority" and read with readConcern: "majority" in a causally consistent session | Slower writes and reads |
| Show it from the app | Update the screen with the value the user just saved | Doesn't fix other devices |
Data that's fine slightly old, like menus, ratings, or restaurant lists, can safely come from replicas.
In Code
const primary = new Pool({ host: 'db-primary' });const replica = new Pool({ host: 'db-replica-1' });// browsing menus: slightly old data is fineasync function getMenu(restaurantId) {return replica.query('SELECT * FROM menu_items WHERE restaurant_id = $1', [restaurantId]);}// user's own data: read-your-own-writes from the primaryasync function getProfile(userId) {return primary.query('SELECT * FROM users WHERE id = $1', [userId]);}
Check how far behind replicas are:
-- run on the primarySELECT client_addr, state, replay_lagFROM pg_stat_replication;
Interview Angle
How to Explain it in an Interview
Common mistakes:
- Saying replication scales writes. It only scales reads.
- Sending every read to replicas without thinking about lag.
- Forgetting that async replication can lose the last few writes during failover.
Summary
1Replication → primary takes writes, replicas copy via WAL / oplog2Gains → high availability + read scaling (not write scaling)3Async (default) → fast, replicas slightly behind, may lose last writes on crash4Sync / majority → safer, slower writes5Replication lag → user reads a replica, sees old data6Fix → read-your-own-writes: own data from primary, shared data from replicasReplicas share reads, but one table can still grow too big for comfortable queries. Next, partitioning splits a large table into smaller pieces on the same server.