The oplog, initial sync, lag and rollback
The capped collection at the heart of replication: what entries look like, how big it should be, what causes replication lag and how rollback works.
- Read oplog entries and know why they are idempotent
- Size the oplog by window, not by bytes
- Diagnose replication lag
- Explain initial sync and rollback
conceptThe concept
Open the interactive lesson to use this diagram.
The oplog (local.oplog.rs) is a special capped collection. Every write on the primary appends entries describing the result of the change: an $inc becomes the new value, so applying an entry twice gives the same result (idempotent). Secondaries fetch entries in batches, apply them in parallel by document, and record their progress (optime).
- Default size: 5% of free disk, between 990 MB and 50 GB. Resize online with
replSetResizeOplog. Since 4.4,oplogMinRetentionHourskeeps entries for a minimum time. - The oplog window is the time between the first and last entry. A member that is offline longer than the window cannot catch up and needs a full initial sync.
- Initial sync clones every database and then applies the oplog accumulated during the copy. File copy based initial sync (Enterprise 5.2+) copies data files instead.
- Rollback: if a primary accepted writes that never replicated to the majority, then failed over, those writes are undone when it rejoins and saved to
rollback/files.
whyWhy it matters
The oplog window is your safety margin for maintenance, network partitions, change stream consumers and backups based on oplog replay. Many teams discover it is only 2 hours during a heavy batch, exactly when a secondary is down for patching.
Open the interactive lesson to use this diagram.
Use caseReal-world scenario
A secondary is taken down for an OS upgrade that runs long. The oplog window during normal traffic is 30 hours, but a bulk re-indexing job generates 10x the usual writes, shrinking the window to 3 hours. The secondary falls off the oplog and needs a 6-hour initial sync of 2 TB. Monitoring the window during batch jobs and sizing the oplog for the worst day avoids this.
Try itExamples
Run and edit these in the interactive lesson.
db.orders.updateOne({ orderNo: "ORD-100050" }, { $inc: { total: 10 } })
db.customers.updateOne({ _id: 12 }, { $unset: { phone: "" }, $set: { tier: "gold" } })
db.getSiblingDB("local").oplog.rs.find({ ns: /^shop\./ }).sort({ $natural: -1 }).limit(2)$inc: 10 is recorded as the resulting total. Re-applying the entry is harmless. (This oplog uses a simplified diff format.)rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()// resize oplog to 100 GB online (run on each member)
db.adminCommand({ replSetResizeOplog: 1, size: 102400 })
// keep at least 48 hours regardless of size
db.adminCommand({ replSetResizeOplog: 1, minRetentionHours: 48 })
// flow control status
db.serverStatus().flowControl
// replication metrics on a secondary
db.serverStatus().metrics.repl.applyinternalsUnder the hood
Replication lag causes: under-provisioned secondaries (slower disks), heavy single-document hot spots (cannot be applied in parallel), large multi-updates generating many entries, index builds on secondaries, network bandwidth between data centres, and read load on secondaries competing with oplog application. Flow control (4.2+) throttles writes on the primary when the majority commit point lags more than flowControlTargetLagSeconds (10 s by default), trading write latency for bounded lag.
Oplog window calculator
Open the interactive lesson to use this diagram.
Avoid / preferDo this, not that
replication: oplogSizeMB: 1024 # busy 2 TB cluster
db.adminCommand({ replSetResizeOplog: 1, size: 51200, minRetentionHours: 48 })The oplog window must outlast your longest maintenance, backup or resync. A tiny oplog on a busy cluster means any secondary down for an hour needs a full initial sync.
db.getSiblingDB("local").oplog.rs.find({ ns: "shop.orders" })db.getSiblingDB("local").oplog.rs.find({
ts: { $gte: Timestamp({ t: 1791446000, i: 0 }) }, ns: "shop.orders"
}).limit(100)The oplog has no secondary indexes, but it is stored in ts order, so a ts lower bound becomes a cheap bounded scan. An ns-only filter reads the whole oplog.
PitfallsCommon mistakes
- Sizing the oplog by bytes without measuring the window under peak write load.
- Running huge
updateManyoperations that produce millions of oplog entries in minutes. - Serving heavy analytics from the same secondaries that must keep up with replication.
- Not alerting on the oplog window and on lag (seconds behind primary).
LimitsWhen not to use it
Applications should not read the oplog directly for change data capture: its format is internal and can change between versions. Use change streams, which are resumable, permission-checked and stable.
SecuritySecurity notes
The oplog contains every write, including sensitive fields. Only backup and CDC tools should be able to read the local database; no application role needs it.
ChallengeTry it yourself
Insert a document into a scratch collection, update it with $inc, delete it, then list the matching oplog entries (op and o) in order.
Show one solution
db.oplog_lab.drop()
db.oplog_lab.insertOne({ _id: 1, qty: 1 })
db.oplog_lab.updateOne({ _id: 1 }, { $inc: { qty: 2 } })
db.oplog_lab.deleteOne({ _id: 1 })
db.getSiblingDB("local").oplog.rs.find({ ns: "shop.oplog_lab" }, { _id: 0, op: 1, o: 1 }).sort({ $natural: 1 })InterviewQuestions you should be able to answer
Why must oplog entries be idempotent?
Secondaries may apply an entry more than once (after a crash during a batch, during initial sync while the copy overlaps the oplog). Recording results (set field to 42) rather than operations (increment by 1) makes repeated application safe.
A secondary is lagging. How do you troubleshoot?
Check rs.printSecondaryReplicationInfo() and lag trend; compare hardware and disk latency of primary vs secondary; look at the write workload (bulk updates, hot documents); check whether secondary reads or index builds compete; check network between sites; inspect metrics.repl.apply and buffer; verify the oplog window is not about to be exceeded. Short term: reduce secondary read load, throttle batches; long term: match hardware, fix workload patterns, enable or tune flow control.
Explain rollback in a replica set.
A primary accepts writes acknowledged with w:1, crashes or is partitioned before replicating them, and another member becomes primary and takes new writes. When the old primary returns, its oplog has diverged; it finds the common point, undoes its unreplicated writes (recover-to-timestamp in modern versions), saves them as BSON in the rollback directory, and resyncs. Majority write concern avoids losing acknowledged writes this way.
QuizCheck your understanding
4 questions with instant feedback in the interactive lesson; a wrong answer goes into your review deck.