On this page

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 writes
2App ─────────────────────────→ [ 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.

PostgreSQLMongoDB
Log that gets copiedWAL (write-ahead log)Oplog (operations log)
Replica nameStandby / read replicaSecondary
Group namePrimary + standbysReplica set
Automatic failoverNeeds a tool (like Patroni) or a managed serviceBuilt in: replicas elect a new primary

Why Use It

BenefitFood app example
High availability: a replica takes over if the primary diesPrimary crashes at 8 PM; a replica becomes primary in seconds and orders keep flowing
Read scaling: replicas share the read trafficMenu browsing (many reads) goes to replicas; placing orders (writes) goes to the primary
Backups and reports: heavy queries run without slowing the primaryDaily 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 later
2Sync: App → Primary writes → waits for replica to confirm → "done" to app
AsynchronousSynchronous
Write speedFastSlower, waits for a replica
If primary crashesLast few writes may be lostNo committed write is lost
DefaultYes, in both PostgreSQL and MongoDBMust be configured
Choose forMost dataData 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 PRIMARY
2t=5 ms App reloads her profile → read goes to REPLICA
3 Replica hasn't received the change yet
4 → shows the OLD address
5 → Riya thinks the save failed and edits again

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

FixHow it worksTrade-off
Read own data from primaryProfile, wallet, and "My Orders" always read from the primaryMore load on the primary
Primary for a short windowAfter a user writes, send their reads to the primary for a few secondsNeeds tracking per user
Majority write + read (MongoDB)Write with w: "majority" and read with readConcern: "majority" in a causally consistent sessionSlower writes and reads
Show it from the appUpdate the screen with the value the user just savedDoesn'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 fine
async 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 primary
async function getProfile(userId) {
return primary.query('SELECT * FROM users WHERE id = $1', [userId]);
}

Check how far behind replicas are:

-- run on the primary
SELECT client_addr, state, replay_lag
FROM pg_stat_replication;

Interview Angle

How to Explain it in an Interview

The 30-Second Spoken Pitch
"Replication keeps copies of the database on several servers. The primary takes all writes and replicas copy every change from its log, the WAL in Postgres or the oplog in MongoDB. It gives high availability, because a replica can take over if the primary fails, and it scales reads, because replicas can serve read traffic. It doesn't scale writes, since every replica applies every write. Replication is usually async, so replicas lag slightly behind. That causes stale reads, like a user updating their address and seeing the old one. I handle that with read-your-own-writes: reads of a user's own data go to the primary, while data that can be slightly old, like menus, goes to replicas. For data I can't lose, I use synchronous or majority writes."

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 / oplog
2Gains → high availability + read scaling (not write scaling)
3Async (default) → fast, replicas slightly behind, may lose last writes on crash
4Sync / majority → safer, slower writes
5Replication lag → user reads a replica, sees old data
6Fix → read-your-own-writes: own data from primary, shared data from replicas

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

Next TopicPartitioning