MongoDB Replication
Replica Set Setup
Initialize Replica Set
// Initialize replica set
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "mongodb1.example.com:27017", priority: 2 },
{ _id: 1, host: "mongodb2.example.com:27017", priority: 1 },
{ _id: 2, host: "mongodb3.example.com:27017", priority: 1 }
]
});
// Simple single-server replica set (development)
rs.initiate();
Add Members to Replica Set
// Add secondary member
rs.add("mongodb4.example.com:27017");
// Add member with specific configuration
rs.add({
_id: 3,
host: "mongodb4.example.com:27017",
priority: 0.5,
votes: 1
});
// Add arbiter (voting only, no data)
rs.addArb("arbiter.example.com:27017");
Remove Members
// Remove member
rs.remove("mongodb4.example.com:27017");
// Remove by member ID
rs.remove(3);
Replica Set Management
Check Replica Set Status
// Get replica set status
rs.status();
// Get replica set configuration
rs.conf();
// Check if current node is primary
rs.isMaster();
// Get replication info
db.getReplicationInfo();
// Check slave status
db.printSlaveReplicationInfo();
Replica Set Configuration
// Get current configuration
config = rs.conf();
// Modify configuration
config.members[1].priority = 2;
config.members[2].hidden = true;
config.version++;
// Apply configuration changes
rs.reconfig(config);
// Force reconfiguration (use with caution)
rs.reconfig(config, {force: true});
Member Roles and Properties
// Priority settings (0-1000, higher = more likely to be primary)
{
_id: 0,
host: "mongodb1.example.com:27017",
priority: 2 // High priority for primary
}
// Hidden member (not visible to applications)
{
_id: 1,
host: "mongodb2.example.com:27017",
priority: 0,
hidden: true // Hidden from read operations
}
// Delayed member (for backup/recovery)
{
_id: 2,
host: "mongodb3.example.com:27017",
priority: 0,
hidden: true,
slaveDelay: 3600 // 1 hour delay
}
// Arbiter (voting only)
{
_id: 3,
host: "arbiter.example.com:27017",
arbiterOnly: true
}
// Non-voting member
{
_id: 4,
host: "mongodb4.example.com:27017",
votes: 0,
priority: 0
}
Read Preferences
Configure Read Preferences
// Primary (default)
db.users.find().readPref("primary");
// Primary preferred
db.users.find().readPref("primaryPreferred");
// Secondary
db.users.find().readPref("secondary");
// Secondary preferred
db.users.find().readPref("secondaryPreferred");
// Nearest (lowest latency)
db.users.find().readPref("nearest");
Read Preference with Tags
// Configure member tags first
config = rs.conf();
config.members[0].tags = { "region": "us-east", "datacenter": "primary" };
config.members[1].tags = { "region": "us-west", "datacenter": "secondary" };
config.version++;
rs.reconfig(config);
// Read from specific tagged members
db.users.find().readPref("secondary", [{ "region": "us-east" }]);
// Multiple tag sets (fallback)
db.users.find().readPref("secondary", [
{ "region": "us-east", "datacenter": "primary" },
{ "region": "us-west" },
{} // Fallback to any secondary
]);
Write Concerns
Write Concern Levels
// Default write concern
db.users.insertOne({name: "John"});
// Acknowledged write (w: 1)
db.users.insertOne(
{name: "John"},
{writeConcern: {w: 1}}
);
// Majority write concern
db.users.insertOne(
{name: "John"},
{writeConcern: {w: "majority", j: true}}
);
// Specific number of acknowledgments
db.users.insertOne(
{name: "John"},
{writeConcern: {w: 2, wtimeout: 5000}}
);
// Unacknowledged write (fire and forget)
db.users.insertOne(
{name: "John"},
{writeConcern: {w: 0}}
);
Custom Write Concern Rules
// Define custom write concern
config = rs.conf();
config.settings = {
getLastErrorModes: {
"allDCs": {
"datacenter": 2
},
"majority": {
"region": 2
}
}
};
config.version++;
rs.reconfig(config);
// Use custom write concern
db.users.insertOne(
{name: "John"},
{writeConcern: {w: "allDCs", wtimeout: 10000}}
);
Failover and Elections
Manual Failover
// Step down primary (triggers election)
rs.stepDown(60); // Step down for 60 seconds
// Step down immediately
rs.stepDown();
// Freeze member (prevent it from becoming primary)
rs.freeze(120); // Freeze for 120 seconds
// Unfreeze member
rs.freeze(0);
Election Control
// Check election status
db.adminCommand({replSetGetStatus: 1}).members.forEach(
function(member) {
print(member.name + ": " + member.stateStr);
}
);
// Force election (use with extreme caution)
db.adminCommand({replSetStepDown: 10, force: true});
Monitoring Replication
Replication Lag
// Check replication lag
rs.printSlaveReplicationInfo();
// Get detailed lag information
db.adminCommand({replSetGetStatus: 1}).members.forEach(
function(member) {
if (member.state !== 1) { // Not primary
var lag = (new Date() - member.optimeDate) / 1000;
print(member.name + " lag: " + lag + " seconds");
}
}
);
Oplog Information
// Switch to local database
use local;
// Check oplog size
db.oplog.rs.stats().maxSize;
// Get oplog information
db.getReplicationInfo();
// Find oplog entries
db.oplog.rs.find().sort({$natural: -1}).limit(5);
// Count oplog entries
db.oplog.rs.count();
Health Checks
// Health check script
function replicaSetHealthCheck() {
var status = rs.status();
var healthy = true;
var issues = [];
status.members.forEach(function(member) {
if (member.health !== 1) {
healthy = false;
issues.push(member.name + " is unhealthy");
}
if (member.state === 1) { // Primary
print("Primary: " + member.name);
} else if (member.state === 2) { // Secondary
var lag = (status.date - member.optimeDate) / 1000;
if (lag > 10) { // More than 10 seconds lag
issues.push(member.name + " has high replication lag: " + lag + "s");
}
}
});
if (healthy && issues.length === 0) {
print("Replica set is healthy");
} else {
print("Issues found:");
issues.forEach(function(issue) {
print("- " + issue);
});
}
}
// Run health check
replicaSetHealthCheck();
Backup and Restore
Backup from Secondary
# Backup from secondary to avoid impacting primary
mongodump --host secondary.example.com:27017 \
--username backup_user \
--password backup_pass \
--authenticationDatabase admin \
--out /backup/$(date +%Y%m%d_%H%M%S)
# Backup specific database
mongodump --host secondary.example.com:27017 \
--db myapp \
--out /backup/myapp_$(date +%Y%m%d)
Point-in-Time Recovery
# Stop MongoDB on target server
sudo systemctl stop mongod
# Restore base backup
mongorestore --host localhost:27017 \
--drop \
/backup/base_backup/
# Replay oplog to specific timestamp
mongorestore --host localhost:27017 \
--oplogReplay \
--oplogLimit 1640995200:1 \
/backup/oplog_backup/
Configuration Examples
Production Replica Set (3 nodes)
rs.initiate({
_id: "production-rs",
members: [
{
_id: 0,
host: "mongo-primary.prod.com:27017",
priority: 2,
tags: { "region": "us-east", "datacenter": "primary" }
},
{
_id: 1,
host: "mongo-secondary1.prod.com:27017",
priority: 1,
tags: { "region": "us-east", "datacenter": "secondary" }
},
{
_id: 2,
host: "mongo-secondary2.prod.com:27017",
priority: 1,
tags: { "region": "us-west", "datacenter": "secondary" }
}
],
settings: {
chainingAllowed: false,
heartbeatIntervalMillis: 2000,
heartbeatTimeoutSecs: 10,
electionTimeoutMillis: 10000,
catchUpTimeoutMillis: 60000,
getLastErrorModes: {
"crossDataCenter": { "datacenter": 2 }
}
}
});
Development Replica Set (single node)
# Start MongoDB with replica set
mongod --replSet dev-rs --dbpath /data/db --port 27017
# Initialize single-member replica set
mongosh --eval "rs.initiate()"
Driver Configuration
Python (PyMongo)
from pymongo import MongoClient, ReadPreference
# Replica set connection
client = MongoClient(
'mongodb://user:pass@mongo1:27017,mongo2:27017,mongo3:27017/mydb?replicaSet=production-rs',
readPreference=ReadPreference.SECONDARY_PREFERRED,
w='majority',
j=True,
serverSelectionTimeoutMS=5000
)
# Read from secondary
db = client.mydb
users = db.users.with_options(
read_preference=ReadPreference.SECONDARY
)
Node.js
const { MongoClient } = require('mongodb');
const uri = 'mongodb://user:pass@mongo1:27017,mongo2:27017,mongo3:27017/mydb?replicaSet=production-rs';
const client = new MongoClient(uri, {
readPreference: 'secondaryPreferred',
w: 'majority',
j: true,
serverSelectionTimeoutMS: 5000,
heartbeatFrequencyMS: 10000
});
// Use specific read preference
const db = client.db('mydb');
const users = db.collection('users').withReadPreference('secondary');