A replica set is a group of Mongo instances that maintain the same dataset or set of data, thus the data will be replicated on different servers achieving high availability of our databases. As for our application, we just need to pass the list of servers to the connection driver we use and it will transparently connect to the correct server.
The topology of a Mongo replica set (RS) defines three figures:
- Primary: Primary server of the RS, clients connect to it by default to execute queries, both reads and writes.
- Secondary: Server with data replicated from the Primary server.
- Arbiter: Server without data, only votes when choosing a new Primary server.
NOTE: Votes to choose a Primary server are cast when there is a change in topology. Mongo does not recommend the use of RS with Arbiters, it is worth setting up an additional node with the replicated dataset.
In this article, uppercase letters will indicate where certain commands should be executed, whether on the Primary, Secondary, or All servers.
ALL
We compile and install MongoDb:
We bind the service to all IPs:
bind_ip = 0.0.0.0
PRIMARY
We access the MongoDb CLI:
We create the admin user:
use admin
db.createUser(
{
user: "admin",
pwd: "PASSWORD",
roles: [ "root" ]
}
)
We create the RS admin user:
db.createUser(
{
user: "clusterAdmin",
pwd: "PASSWORDRS",
roles: [ "root" ]
}
)
TODOS
We enable authentication:
security:
authorization: enabled
We restart the service:
PRIMARY
Mongo RS nodes communicate securely with each other either through SSL certificates that must be renewed every X time or through key files.
We generate the key files:
chmod 400 /etc/mongodb.key
chown mongodb:mongodb /etc/mongodb.key
We copy the key to all RS servers and assign them the same permissions as before.
TODOS
security:
keyFile: /etc/mongodb.key
replication:
replSetName: rs0
We restart the service:
PRIMARY
rs.initiate(
{
_id : 'rs0',
members: [
{ _id : 0, host : "kr0mtest:27017" },
{ _id : 1, host : "kr0mtest2:27017" },
{ _id : 2, host : "kr0mtest3:27017" }
]
}
)
rs0:SECONDARY>
After a while, a PRIMARY will be elected:
rs0:PRIMARY> rs.status()
{
"set" : "rs0",
"date" : ISODate("2020-04-17T10:38:46.841Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1587119903, 1),
"members" : [
{
"_id" : 0,
"name" : "kr0mtest:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 265286,
"optime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-04-17T10:38:43Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1586854672, 1),
"electionDate" : ISODate("2020-04-14T08:57:52Z"),
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "kr0mtest2:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 84614,
"optime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-04-17T10:38:43Z"),
"optimeDurableDate" : ISODate("2020-04-17T10:38:43Z"),
"lastHeartbeat" : ISODate("2020-04-17T10:38:44.999Z"),
"lastHeartbeatRecv" : ISODate("2020-04-17T10:38:44.998Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "kr0mtest3:27017",
"syncSourceHost" : "kr0mtest3:27017",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "kr0mtest3:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 265265,
"optime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-04-17T10:38:43Z"),
"optimeDurableDate" : ISODate("2020-04-17T10:38:43Z"),
"lastHeartbeat" : ISODate("2020-04-17T10:38:45.870Z"),
"lastHeartbeatRecv" : ISODate("2020-04-17T10:38:45.888Z"),
"pingMs" : NumberLong(1),
"lastHeartbeatMessage" : "",
"syncingTo" : "kr0mtest:27017",
"syncSourceHost" : "kr0mtest:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1587119923, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1587119923, 1),
"signature" : {
"hash" : BinData(0,"xSsKDy+0YUJcBM4vpFN0VaJa+rg="),
"keyId" : NumberLong("6815488928334741505")
}
}
}