Monday, May 28, 2018

Setting up mongodb replication

Mongodb needs at least 2 servers, preferably 3, to setup a proper mongodb replication. In this article, we will use below hostname as our mongodb nodes: mongo-1 (primary) mongo-2 mongo-3

Make sure mongodb is installed in all servers.

Set mongodb repo:

mongo-1: $ cat > mongodb.repo << EOF >[mongodb]
>name=MongoDB Repository
mongo-1: $ sudo mv mongodb.repo /etc/yum.repos.d/

Install mongodb:
mongo-1: $ sudo yum install -y mongodb-org

Set /etc/hosts for each server as below:
mongo-1: $ cat >> hosts << EOF mongo-1 mongo-2 mongo-3
mongo-1: $ sudo mv /etc/hosts /etc/hosts.original
mongo-1: $ sudo mv hosts /etc/

To ease up this installation, turn off firewall and set selinux to permissive mode, temporarily, in all servers.
mongo-1: $ sudo systemctl stop firewalld mongo-1: $ sudo setenforce 0

Edit /etc/mongod.conf in every server, to be similar as below (assuming we are using myreplica as our replSet)

mongo-1: $ sudo cat /etc/mongod.conf 

Once editing is done, restart mongodb in each server
mongo-1: $ sudo systemctl restart mongod

On the first server initiate mongo replica:
mongo-1: $ sudo mongo
MongoDB shell version: x.x.x
connecting to: test
Server has startup warnings: 
2018-05-28T04:39:22.580+0000 [initandlisten] 
2018-05-28T04:39:22.580+0000 [initandlisten] ** WARNING: Readahead for /var/lib/mongo is set to 4096KB
2018-05-28T04:39:22.580+0000 [initandlisten] **          We suggest setting it to 256KB (512 sectors) or less
2018-05-28T04:39:22.580+0000 [initandlisten] **
myreplica:PRIMARY> rs.initiate() 

Add the other server, namely mongo-2 and mongo-3 to the replicaset
myreplica:PRIMARY> rs.add("mongo-2")
myreplica:PRIMARY> rs.add("mongo-3")

Run rs.status() to see the status of our replica
myreplica:PRIMARY> rs.status() 
        "set" : "myreplica",
        "date" : ISODate("2018-05-28T05:32:10Z"),
        "myState" : 1,
        "members" : [
                        "_id" : 0,
                        "name" : "mongodb01.novalocal.local:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 11,
                        "optime" : Timestamp(1604978545, 5),
                        "optimeDate" : ISODate("2018-05-28T05:32:10Z"),
                        "electionTime" : Timestamp(1604626688, 1),
                        "electionDate" : ISODate("2018-05-28T05:32:10Z"),
                        "self" : true
        "ok" : 1

In order to rectify the "stateStr: UNKNOWN" and "lastHeartbeatMessage: still initializing", simply add the name of the primary server, as given by mongodb in /etc/hosts of all secondary servers

mongo-2: $ cat /etc/hosts mongo-1 mongodb-1.novalocal mongo-2 mongo-3 

mongo-3: $ cat /etc/hosts mongo-1 mongodb-1.novalocal mongo-2 mongo-3 

You should be getting "syncingTo : mongodb-1.novalocal:27017", and "stateStr: SECONDARY" when you run rs.status() in primary server

myreplica:PRIMARY> rs.status()
                        "_id" : 2,
                        "name" : "mongo-3:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 368,
                        "optime" : Timestamp(1527485519, 1),
                        "optimeDate" : ISODate("2018-05-28T05:31:59Z"),
                        "lastHeartbeat" : ISODate("2018-05-28T05:38:06Z"),
                        "lastHeartbeatRecv" : ISODate("2018-05-28T05:38:06Z"),
                        "pingMs" : 1,
                        "syncingTo" : "mongodb-1.novalocal:27017"

Your replica is now complete. To test it out:

Create new database in primary server, and fill up with data
myreplica:PRIMARY> use mynewdb
... {
...     "name": "myreplica",
...     "description":  "this is my new mongodb replica",
...     "hosts" : [ "mongo-1", "mongo-2", "mongo-3" ],
... })
WriteResult({ "nInserted" : 1 })
myreplica:PRIMARY> show dbs
admin      (empty)
local      2.077GB
mynewdb    0.078GB
myreplica:PRIMARY> show collections;
myreplica:PRIMARY> db.stack.find()
{ "_id" : ObjectId("5b0b97f9aca2dd0afb9d86a5"), "name" : "myreplica", "description" : "this is my new mongodb replica", "hosts" : [ "mongo-1", "mongo-2", "mongo-3" ] }

Login to secondary servers, sync (by running "rs.slaveOk()" ) and check whether the data gets replicated

myreplica:SECONDARY> use mynewdb
switched to db mynewdb
myreplica:SECONDARY> show collections
2018-05-28T05:51:42.601+0000 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:131
myreplica:SECONDARY> rs.slaveOk()
myreplica:SECONDARY> show collections
myreplica:SECONDARY> db.stack.find()
{ "_id" : ObjectId("5b0b97f9aca2dd0afb9d86a5"), "name" : "myreplica", "description" : "this is my new mongodb replica", "hosts" : [ "mongo-1", "mongo-2", "mongo-3" ] }

Done :)

No comments: