⚡ MongoDB Replication
Master replica sets with live simulations, interactive demos, and comprehensive examples
🎯 What is Replication? (Simple Explanation)
Imagine you're writing an important document. Would you:
- 💾 Save it on ONE computer only? (What if that computer crashes?)
- ☁️ Keep multiple copies on different computers? (Smart! If one fails, you have backups!)
That's exactly what MongoDB replication does!
📚 Simple Definition:
Replication = Keeping multiple synchronized copies of your data on different servers
It answers critical questions:
• What if a server crashes? (Automatic failover!)
• What if you need maintenance? (Zero downtime!)
• What if the data center loses power? (Data is safe!)
• What if you need to scale reads? (Read from replicas!)
🏦 Real-World Analogy: Bank Branches
Think of a bank with multiple branches:
- Main Branch (Primary): Where all account updates happen first
- Other Branches (Secondaries): Get copies of all account data
- Security Guard (Arbiter): Helps decide which branch becomes main if original closes
If the main branch suddenly closes:
- Another branch automatically becomes the main branch
- Customers don't even notice the switch!
- All their data is safe and accessible
- Banking continues without interruption
This is exactly how MongoDB replication works! Let's see it in action... 👇
🎮 Interactive Demo: Watch It Work!
Click the buttons below to see replication and failover in real-time
Watch what happens when you write data or crash the PRIMARY!
💻 Live Console: See MongoDB Commands
Watch real MongoDB commands execute in real-time
🎭 The 3 Types of Servers
Every server in a replica set has a specific job
The Boss Server - Only one allowed at a time
- Takes ALL write requests (insert, update, delete)
- Can answer read requests
- Records everything it does
- Sends copies to SECONDARYs
// All writes go here
db.users.insertOne({
name: "Alice"
})
The Backup Servers - Usually have 2 or more
- Keeps exact copy of PRIMARY's data
- Can answer read requests
- Can become PRIMARY if needed
- Automatically syncs all changes
// Continuously syncing
PRIMARY makes change
→ SECONDARY copies it
→ Now both have same data!
The Tie-Breaker - Optional, lightweight
- Does NOT store any data
- Only votes in elections
- Cannot become PRIMARY
- Saves money (no storage needed)
// When to use:
2 servers + 1 arbiter
= Cheaper than 3 full servers
= Still get automatic failover!
🌊 How Data Flows (Step by Step)
Let's follow a single piece of data through the system
await db.users.insertOne({ name: "Alice", age: 25 })
// PRIMARY's database now has:
{ _id: ObjectId("..."), name: "Alice", age: 25 }
// Oplog entry:
{
op: "insert",
ns: "mydb.users",
o: { name: "Alice", age: 25 }
}
SECONDARY-1: "I'll copy that insert!"
SECONDARY-2: "Me too!"
// Now ALL 3 servers have:
{ _id: ObjectId("..."), name: "Alice", age: 25 }
✅ Data is replicated!
⚡ This happens in milliseconds! Your app doesn't wait for secondaries - PRIMARY responds immediately, and secondaries catch up automatically in the background.
💥 What If PRIMARY Crashes?
This is where the magic happens - Automatic Failover!
// Watch how a new PRIMARY is elected automatically
⏱️ The 12-Second Failover Timeline
CRASH! PRIMARY server loses power / crashes / network fails
❌ mongodb-01 (PRIMARY) → OFFLINE
SECONDARYs notice: "Hey, PRIMARY isn't responding to our heartbeats!"
mongodb-02: "No heartbeat from PRIMARY for 10 seconds"
mongodb-03: "Same here, PRIMARY must be down!"
Election time! SECONDARYs vote for a new PRIMARY
mongodb-02: "I nominate myself!"
mongodb-03: "I vote for mongodb-02" (has fresher data)
mongodb-02: "I vote for myself"
🎉 mongodb-02 WINS with 2 votes!
New PRIMARY elected! Service restored, your app reconnects automatically
❌ mongodb-01 → Still offline
👑 mongodb-02 → NEW PRIMARY (promoted!)
📚 mongodb-03 → SECONDARY
✅ Your app automatically finds new PRIMARY
✅ Writes resume
✅ Users never knew there was a problem!
🎯 Key Takeaway
- ⏱️ Total downtime: ~12 seconds
- 💾 Data lost: ZERO
- 👨💻 Human intervention needed: NONE
- 😴 Users affected: Barely notice!
📖 Where Should You Read Data From?
You have 3 servers - which one should answer read queries?
- Always get latest data (freshest!)
- But PRIMARY gets overwhelmed with traffic
- Best for: Critical data that MUST be current
// Default behavior
db.users.find()
// Goes to PRIMARY
- Takes load off PRIMARY
- But might read slightly old data (lag)
- Best for: Reports, analytics, non-critical
// Specify secondary
db.users.find()
.readPref('secondary')
// Goes to SECONDARY
- Reads from closest server
- Best performance (low latency)
- Best for: Global apps, speed matters
// Find nearest
db.users.find()
.readPref('nearest')
// Goes to closest server
🚀 How to Set It Up (Simple Version)
# Terminal 1 - Start first server
mongod --replSet myReplica --port 27017 --dbpath /data/db1
# Terminal 2 - Start second server
mongod --replSet myReplica --port 27018 --dbpath /data/db2
# Terminal 3 - Start third server
mongod --replSet myReplica --port 27019 --dbpath /data/db3
# Note: All use same replica set name "myReplica"
# Connect to first server
mongosh --port 27017
# Initialize replica set (run this ONCE)
rs.initiate({
_id: "myReplica",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
})
# Wait ~10 seconds, then check:
rs.status()
# You'll see:
# • One PRIMARY
# • Two SECONDARYs
# 🎉 Replica set is ready!
const { MongoClient } = require('mongodb');
// Connection string lists ALL servers
const uri = "mongodb://localhost:27017,localhost:27018,localhost:27019/mydb?replicaSet=myReplica";
const client = new MongoClient(uri);
await client.connect();
// Write (automatically goes to PRIMARY)
await db.users.insertOne({ name: "Alice" });
// Read (goes to PRIMARY by default)
const users = await db.users.find().toArray();
// That's it! Driver handles everything:
// ✅ Finds PRIMARY automatically
// ✅ Routes writes to PRIMARY
// ✅ Handles failover automatically
// ✅ Reconnects if PRIMARY changes
❓ Common Questions (Answered Simply)
Minimum: 3 servers
Why 3? You need a majority to elect a new PRIMARY:
• With 3 servers: Need 2 votes (majority) ✅
• With 2 servers: Need 2 votes, but if 1 dies, only 1 vote left (no majority) ❌
Recommended: 3 for small apps, 5+ for critical production apps
NO data loss if you use write concern "majority"
This tells MongoDB: "Don't say 'success' until most servers have the data"
// Safe write (waits for majority)
await db.users.insertOne(
{ name: "Alice" },
{ writeConcern: { w: "majority" } }
);
// MongoDB waits until 2 out of 3 servers have the data
// Even if PRIMARY crashes right after, data is safe! ✅
🎓 What You Learned
✅ 3 server types: PRIMARY (writes), SECONDARY (backups), ARBITER (votes)
✅ Data flows: App → PRIMARY → Oplog → SECONDARYs
✅ Failover takes ~12 seconds, ZERO data loss
✅ You can read from PRIMARY (fresh) or SECONDARY (faster)
✅ Minimum 3 servers for automatic failover
✅ MongoDB handles everything automatically!
💾 Write Concern: Ensuring Data Safety
Write concern is one of the most important concepts for production MongoDB deployments. It determines when MongoDB acknowledges a write operation.
What is Write Concern?
Write concern describes the level of acknowledgment requested from MongoDB for write operations. It's the difference between "the write succeeded on PRIMARY" vs "the write succeeded AND is safely replicated."
w: 1 (Default - Fast but Risky)
MongoDB acknowledges write after PRIMARY writes to memory.
// Default behavior
await db.users.insertOne({ name: "Alice" })
// Returns immediately after PRIMARY writes
// Secondaries may not have data yet!
// If PRIMARY crashes right now:
// ❌ Data might be lost!
// ❌ Secondaries don't have it yet
w: "majority" (Recommended)
MongoDB acknowledges after majority of nodes have the data.
// Safe for production
await db.users.insertOne(
{ name: "Alice" },
{ writeConcern: { w: "majority" } }
)
// Returns after 2 out of 3 nodes confirm
// If PRIMARY crashes now:
// ✅ Data is safe on majority!
// ✅ Will survive failover
w: 3 (Maximum Safety)
MongoDB acknowledges after ALL nodes have the data.
// Maximum safety
await db.users.insertOne(
{ name: "Alice" },
{ writeConcern: { w: 3 } }
)
// Returns after ALL 3 nodes confirm
// Slowest option
// Can block if any node is down!
📊 Write Concern Comparison
| Write Concern | Acknowledgment | Speed | Safety | Use Case |
|---|---|---|---|---|
w: 1 |
PRIMARY only | 🟢 Fastest | 🔴 Lowest | Logs, analytics, non-critical |
w: "majority" |
Majority of nodes | 🟡 Moderate | 🟢 High | Production default |
w: 3 |
All nodes | 🔴 Slowest | 🟢 Maximum | Financial transactions |
Additional Write Concern Options
await db.collection.insertOne(
{ data: "important" },
{
writeConcern: {
w: "majority", // Wait for majority
j: true, // Wait for journal (survives restart)
wtimeout: 5000 // Timeout after 5 seconds
}
}
)
// j: true = data written to journal on disk
// Survives mongod crash/restart
// Slightly slower but more durable
// wtimeout = max milliseconds to wait
// Prevents indefinite blocking
// Throws error if timeout exceeded
Set default write concern to
"majority" at connection level:
const uri = "mongodb://localhost:27017/mydb?replicaSet=rs0&w=majority&journal=true";
// OR in code:
const client = new MongoClient(uri, {
writeConcern: {
w: "majority",
j: true,
wtimeout: 5000
}
});
// Now all writes are safe by default!
📊 Monitoring & Troubleshooting
Proper monitoring is essential for maintaining a healthy replica set. Here are the key commands and metrics to track.
rs.status()
Complete replica set state
rs.status()
// Shows for each member:
// • Current state
// • Health (0=down, 1=up)
// • Replication lag
// • Last heartbeat time
rs.printReplicationInfo()
Oplog window details
rs.printReplicationInfo()
// Output:
configured oplog size: 5GB
log length: 48000s (13hrs)
// If too small, increase!
rs.printSecondaryReplicationInfo()
Replication lag for each secondary
rs.printSecondaryReplicationInfo()
// Shows lag for each:
mongodb-02: 2 secs behind ✅
mongodb-03: 45 secs behind ⚠️
1. High Replication Lag (>10 seconds):
• Cause: Slow secondary, heavy writes, network issues
• Solution: Scale hardware, reduce write load
2. Oplog Window Too Small:
• Cause: High write volume, small oplog
• Solution: Increase oplog size (requires restart)
3. Frequent Elections:
• Cause: Network instability, misconfigured priorities
• Solution: Fix network, adjust priorities
💼 Interview Questions & Answers
Click any question to expand the detailed answer.