Author: Francis Ndungu
Last Updated: Thu, Apr 7, 2022When you deploy a MongoDB database in a mission-critical application, you can configure a replica set for high availability. A replica set offers redundancy and high availability, which reduces downtime during a disaster because there is no single point of failure. The minimum recommended configuration for a MongoDB replica set is one primary node and two secondary nodes, but replica sets can have up to 50 members. Your application writes only to the primary node, and the secondary nodes replicate the data. If the primary node fails, the replica set holds an election to choose a new primary. Applications can read data from secondaries but cannot write to them.
This guide explains how to create a MongoDB replica set. It was tested on Ubuntu 20.04, but the steps are similar for other Linux distributions.
You need three servers attached to the same Vultr VPC. Each of the servers should have:
MongoDB installed and secured with a password
For clarity, this guide uses the following hostnames and private IP addresses for the servers. You should substitute these with your values.
MongoDB recommends using DNS hostnames instead of IP addresses for the replica members. Because the Vultr VPC is a private network without DNS, add the private IP addresses and hostnames to the hosts file. Repeat these steps on each server.
Edit the hosts file.
$ sudo nano /etc/hosts
Locate the line below.
127.0.0.1 localhost
Enter the IP addresses and hostnames as shown under that line.
127.0.0.1 localhost
10.0.0.1 server-1
10.0.0.2 server-2
10.0.0.3 server-3
Save and close the file.
All servers in the replica set share a base64 key. Follow these steps to install the key.
Use the openssl
command to generate a new key on one of the servers.
$ openssl rand -base64 756
You should get a block like this. Copy this base64 key. You'll use it in the following steps.
Yga80PbkHKptRRoONFCPaPzOCFpySgpwNHMA3JS179wyGCOIOYg/FUnDyiIhGe5D
YVQF3o+SliscBiKftsPZ5WBojRREcefAUHOqK7pVBOjT+oYuH6ltMGiDtH26XjVB
... truncated ...
yxJm+UjpN0n8V1pH1LrMJT4FC4Bw3L7vqSnxVbLRnQIiO2Y0ECfyPgepCCNIyuaP
mMSUJ8mmlq4jdfoAKvCspeliSQ/cqaxKfqaTWjzhsLk8eHbU
Repeat these steps on each server.
Create a new auth_key file.
$ sudo nano /var/lib/mongodb/auth_key
Paste your base64 key.
Set the permissions to 400, making the file read-only for the file owner and access denied for all others.
$ sudo chmod 400 /var/lib/mongodb/auth_key
Change the owner and group to mongodb.
$ sudo chown mongodb:mongodb /var/lib/mongodb/auth_key
In this section, you'll configure the shared key, network interface, and replica set name. Repeat these sub-sections on each server.
Open mongod.conf in an editor for the following steps.
$ sudo nano /etc/mongod.conf
Find the security section.
security:
authorization: enabled
#operationProfiling:
Below the authorization: line, add the keyFile value as shown.
security:
authorization: enabled
keyFile: /var/lib/mongodb/auth_key
#operationProfiling:
Find the network interfaces section.
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1
Add the respective server name after the loopback interface (127.0.0.1) to each server. For example:
On server-1:
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1, server-1
On server-2:
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1, server-2
On server-3:
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1, server-3
Find the replication section.
#replication:
Remove the # comment from the replication line. Below that, add replSetName: "rs0"
as shown.
replication:
replSetName: "rs0"
Restart MongoDB on the primary node.
$ sudo systemctl restart mongod
Restart MongoDB on the secondary nodes.
$ sudo systemctl restart mongod
In this section, you'll add the nodes to the replica set and bootstrap the replication process.
On the primary node, log in to MongoDB.
$ mongosh -u your_admin_name -p --authenticationDatabase admin
Enter the password for your admin account and press ENTER to proceed.
Run the following command to add the replica set members.
test> rs.initiate(
{
_id: "rs0",
members: [
{ _id: 0, host: "server-1" },
{ _id: 1, host: "server-2" },
{ _id: 2, host: "server-3" }
]
})
You should get the following response when the replica set starts. Notice the prompt changes to rs0 [direct: secondary] test>
.
{ ok: 1 }
rs0 [direct: secondary] test>
Create a sample company_db database.
rs0 [direct: secondary] test> use company_db
You should get the following response and the prompt changes to rs0 [direct: primary] company_db>
. This member is now the primary node.
switched to db company_db
rs0 [direct: primary] company_db>
Insert a sample record in a new employees collection in the company_db database.
rs0 [direct: primary] company_db> db.employees.insertOne({
"staff_id" : 1,
"staff_name" : "JOHN DOE",
"phone" : "11111111"
})
You should get the output below.
{
acknowledged: true,
insertedId: ObjectId("621dcf1abdb5b0c5e59294d9")
}
On each secondary node, log in to MongoDB.
$ mongosh -u your_admin_name -p --authenticationDatabase admin
Enter the password for your admin account and press ENTER to proceed.
You should see the prompt below, showing that the members are secondary nodes.
rs0 [direct: secondary] test>
On each secondary node, switch to the company_db.
rs0 [direct: secondary] test> use company_db
You should get the following output.
switched to db company_db
Run the following command on each secondary node, which allows them to accept read commands.
rs0 [direct: secondary] company_db> db.getMongo().setReadPref('primaryPreferred')
List the document from the employees collection.
rs0 [direct: secondary] company_db> db.employees.find()
You should get the following output on each secondary node, which shows that the replica set replicated the data to each node.
[
{
_id: ObjectId("621dcf1abdb5b0c5e59294d9"),
staff_id: 1,
staff_name: 'JOHN DOE',
phone: '11111111'
}
]
Try adding a new employee record on any secondary node.
rs0 [direct: secondary] company_db> db.employees.insertOne({
"staff_id" : 2,
"staff_name" : "MARY ROE",
"phone" : "22222222"
})
The command should fail. Secondary nodes are read-only.
MongoServerError: not primary
If you stop the primary server or it goes offline, the replica set elects one of the secondary nodes to be the new primary node.
$ sudo systemctl stop mongod
For application reliability and data recovery, always consider replication for MongoDB instances. If your MongoDB replica set is working as expected, you can learn more about MongoDB and MongoDB replica sets in the MongoDB documentation Replication section.
You also need to consider how to handle failover in your client application. As explained in the documentation:
If an operation fails because of a network error, ConnectionFailure is raised, and the client reconnects in the background.