MongoDB Replication (Replica Sets)¶
A MongoDB replica set is a group of mongod instances holding the same data set, with one primary accepting writes and secondaries replicating from it — similar in spirit to PostgreSQL streaming replication, but with built-in automatic failover via election. See Security first if TLS/keyfile auth is unfamiliar.
Quick Test Setup (No Auth)¶
Start three instances on different ports:
mkdir ~/mongod{1,2,3}
mongod --dbpath ~/mongod1 --port 27001 --replSet myset --logpath ~/mongod1/mongod1.log --logappend --oplogSize 50 --fork
mongod --dbpath ~/mongod2 --port 27002 --replSet myset --logpath ~/mongod2/mongod2.log --logappend --oplogSize 50 --fork
mongod --dbpath ~/mongod3 --port 27003 --replSet myset --logpath ~/mongod3/mongod3.log --logappend --oplogSize 50 --fork
Connect to the first and define the set:
mongo --port 27001
cfg = {
_id: "myset",
members: [
{ _id: 0, host: "mongo1.example.local:27001" },
{ _id: 1, host: "mongo1.example.local:27002" },
{ _id: 2, host: "mongo1.example.local:27003" }
]
}
rs.initiate(cfg)
Check Status¶
rs.status()
Key fields per member: stateStr (PRIMARY/SECONDARY/etc.), health, optimeDate (how current that member's data is), and syncingTo (which member it's replicating from).
db.isMaster()
Shows the current primary, the full member list, and basic wire-protocol info — a quick way to confirm which node an application will actually be routed to write against.
Adding and Removing Members¶
rs.add({ _id: 3, host: "mongo1.example.local:27020" })
rs.remove("mongo1.example.local:27020")
Configure a Member to Never Become Primary¶
Useful for an arbiter, a reporting/analytics secondary, or a geographically distant DR node you don't want winning elections under normal conditions.
cfg = rs.conf()
cfg.members[2].priority = 0
rs.reconfig(cfg)
A priority of 0 makes that member ineligible for election but it still replicates and can still be read from (subject to read preference).
Keyfile-Secured Replica Set¶
For internal member-to-member authentication (separate from client-facing user auth — see Security):
openssl rand -base64 756 > /etc/mongodb/repl.key
chmod 0400 /etc/mongodb/repl.key
Start each member with the keyfile and --auth:
mkdir -p /tmp/mongo/keyfileReplSet/replSet{1,2,3}
mongod --keyFile /etc/mongodb/repl.key --replSet keyfileReplSet --dbpath=/tmp/mongo/keyfileReplSet/replSet1 \
--logpath=/tmp/mongo/keyfileReplSet/replSet1/mongo.log --port 31210 --fork --auth
mongod --keyFile /etc/mongodb/repl.key --replSet keyfileReplSet --dbpath=/tmp/mongo/keyfileReplSet/replSet2 \
--logpath=/tmp/mongo/keyfileReplSet/replSet2/mongo.log --port 31211 --fork --auth
mongod --keyFile /etc/mongodb/repl.key --replSet keyfileReplSet --dbpath=/tmp/mongo/keyfileReplSet/replSet3 \
--logpath=/tmp/mongo/keyfileReplSet/replSet3/mongo.log --port 31212 --fork --auth
Every member of a given replica set must use the identical keyfile — a mismatch prevents members from authenticating to each other, and shows up as members unable to reach quorum even though each mongod process is individually healthy.
TLS-Secured Replica Set¶
Combines the TLS setup from Security with a multi-member replica set:
mkdir -p /tmp/mongo/encryptedReplSet/replSet{1,2,3,4}
mongod --sslMode requireSSL --sslPEMKeyFile /home/mongodb/server.pem --sslCAFile /home/mongodb/ca.crt \
--replSet encryptedReplSet --dbpath=/tmp/mongo/encryptedReplSet/replSet1 \
--logpath=/tmp/mongo/encryptedReplSet/replSet1/mongo.log --port 27017 --fork
# repeat for replSet2 (port 27018), replSet3 (port 27019), replSet4 (port 27020)
Connect and initiate as usual, using the TLS-flagged mongo invocation:
mongo --host mongo1.example.local --ssl --sslPEMKeyFile /home/mongodb/client.pem --sslCAFile /home/mongodb/ca.crt
rs.initiate({
_id: "encryptedReplSet",
version: 1,
members: [
{ _id: 0, host: "mongo1.example.local:27017" },
{ _id: 1, host: "mongo1.example.local:27018" },
{ _id: 2, host: "mongo1.example.local:27019" }
]
})
If a member gets left out of the initial config (easy to do when scripting several mongod starts), add it afterward the normal way — no need to redo rs.initiate:
rs.add({ _id: 3, host: "mongo1.example.local:27020" })
A Common Startup Warning: Transparent Huge Pages¶
Not a replication-specific issue, but frequently first noticed when standing up several mongod instances at once for a replica set test. See Troubleshooting: Transparent Huge Pages for the fix.
Related¶
- Security — the TLS certificates and keyfile referenced above
- Sharding — combining replica sets with sharding for horizontal write scaling, not just HA
- Troubleshooting — startup warnings and OS-level tuning