Andrew Mercer
on this page

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.

  • 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