preface

To ensure high availability of databases, a single node is not enough. In production environments, cluster deployment is usually used to provide data redundancy and ensure high availability of databases. There are two main types of clusters in MongoDB, replica set and shard cluster. The former provides data redundancy and availability, while the latter can improve the throughput of the system. This article introduces the concept and configuration of replica sets.

Replication Replica set description

Replica set member

For details on replica sets, see the official documentation.

Replication is a set of Mongod instances that maintain the same set of data. The copy set contains several data nodes and arbiters. Among the data nodes, there is only one member (Primary) and the other member (Secondary).

The minimum recommended configuration for a replica set is a three member replica set with three data-bearing members: one primary and two secondary members. In some circumstances (such as you have a primary and a secondary but cost constraints prohibit adding another secondary), you may choose to include an arbiter. An arbiter participates in elections but does not hold data (i.e. does not provide data redundancy).

The following figure shows a typical 3-node architecture (with resources to deploy two slave nodes, and one of them to a quorum node if not available).

  • Primary node

A unique node in a replica set that supports read and write operations. Write operations are generally recorded in Oplog.

  • Secondary node

A data node that has the same copy of data as the master node and is generally read-only. The secondary node asynchronously synchronizes data from the oplog of the primary node. Secondary nodes do not vote (priority: 0)

  • Arbiter node (Arbiter)

A node is only used for voting, does not store data copies, and can be deployed when resources are tight. It is not recommended when resources are sufficient.

Replica set schema

  • The minimum configuration of the production environment is officially recommended as 3 nodes, 1 Primary node and 2 Secondary nodes. In the case of resource shortage, 1 Secondary node can be converted to Arbiter.
  • A replica set can have a maximum of 50 members, but only 7 voting members.
  • When there are more than 2 nodes. It is recommended that the replica set have an odd number of members instead of quorum (to prevent the split brain caused by network anomalies in remote data centers).
  • A vote can be taken only when the number of voting nodes exceeds half of the total number of nodes.
Number of nodes To elect a new node Number of nodes that can fail
3 2 1
4 3 1
5 3 2
6 4 2

Automatic failover (HA)

MongoDB runs in the replica set architecture. When the master node fails, the replica set will fail over, and the remaining nodes will elect new master nodes. The elected primary node continues to provide services. After the original faulty primary node is repaired, it is automatically added to the replica set as a secondary node.

  • After the primary node is faulty (electionTimeoutMillisIn cannot pass with other nodes, default 10s), in the case of meeting election requirementsleaseTimeThe node election is completed in seconds (default 30s).
  • Before MongoDB R3.2.0, the election protocol was based on Bully algorithm. Since R3.2.0, the election strategy based on Raft algorithm is used by default.
  • The number of nodes participating in the election is greater than half of the total number of nodes in the replica set.
  • The replica set cannot process writes until the election is successful. If read requests are configured to run on slave nodes, the replica set can continue to process them when the primary node goes offline.

Node read operation

  • The primary node can read and write data, while the secondary node can only read data.
  • By default, the MongoDB client can only read data from the master node when the master node is working properly.
  • If you need to read data from the slave node, you can passslaveOkReadPreferenceConfigure.
    • Set in the slave noders.slaveOk()After that, the client can read data from the slave node.
    • More fine-grained data read configurations are available through configurationReadPreference. Mongo shell can execute commandsdb.getMongo().setReadPref('secondary')Settings.
model describe
primary Read data only from the primary node, which is the default
primaryPreferred Read data from primary first. Primary is not serviceable. Read data from secondary
secondary Read data only from the scondary node
secondaryPreferred Read from secondary first, or from primary if there is no secondary member
nearest Read nearest according to network distance

Set up Replica Set in Docker environment

Basic environment

  • Ubuntu16.04
  • Docker19.03
  • Docker Compose1.25.1 — rc1
  • MongoDB4.2.8

As the configuration of replica set requires multiple nodes, Docker is used here for quick installation. Except for the installation, the MongoDB configuration is the same as the local installation. For local installation, refer to the official documentation.

The configuration process

  1. Start three MongoDB instances using the docker command.
docker run -d \ --name mongo1 \ -p 37017:27017 \ -v /home/mongodb/replset/mongo1/mongod.conf:/data/configdb/mongod.conf \ v/home/mongo/replset mongo1 / data: / data/db \ mongo: 4.2.8 - config/data/configdb mongod. Conf docker run - d \ -- the name  mongo2 \ -p 37018:27017 \ -v /home/mongodb/replset/mongo2/mongod.conf:/data/configdb/mongod.conf \ -v / home/mongo/replset mongo2 / data: / data/db \ mongo: 4.2.8 - config/data/configdb mongod. Conf docker run - d \ -- the name mongo3 \ -p 37019:27017 \ -v /homer/mongodb/replset/mongo3/mongod.conf:/data/configdb/mongod.conf \ -v / home/mongo/replset mongo3 / data: / data/db \ mongo: 4.2.8 - config/data/configdb mongod. ConfCopy the code

The configuration file

# mongod.conf

# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /data/db Configure the location where data is stored
  journal:
    enabled: true
# engine:
# mmapv1:
# wiredTiger:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log # log file

# network interfaces
net:
  port: 27017
  bindIp: 0.0. 0. 0 # Configure network

# how the process runs
processManagement:
  timeZoneInfo: /usr/share/zoneinfo

#security:
  #keyFile:
#operationProfiling:

#replication:
replication:
   replSetName: rs Define the name of the replica set

#sharding:

## Enterprise-Only Options:

#auditLog:

#snmp:
Copy the code
  1. Assuming mongo1 as the master node, go to the master node and execute mongo to enter the Mongo shell.
Rs. Initiate ({" _id ":" rs "and" members ": [{" _id" : 1, "the host" : "172.17.218.94:37017"}, {" _id ": 2," the host ": "172.17.218.94:37018"}, {" _id ": 3," the host ":" 172.17.218.94:37019 "})})Copy the code

If the following information is displayed, the configuration is successful.

{
        "ok" : 1."$clusterTime" : {
                "clusterTime" : Timestamp(15964565601),"signature" : {
                        "hash" : BinData(0."AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)}},"operationTime" : Timestamp(1596456560, 1)}Copy the code

After ten seconds, you can find that the terminal has changed:

rs:PRIMARY>
Copy the code

To view the status of the current replication set, run rs.status() :

# ignore some arguments {"set": "rs"."members": [{"_id": 1."name": "172.17.218.94:37017"."health": 1."state": 1."stateStr": "PRIMARY"
        },
        {
            "_id": 2."name": "172.17.218.94:37018"."health": 1."state": 2."stateStr": "SECONDARY"
        },
        {
            "_id": 3."name": "172.17.218.94:37019"."health": 1."state": 2."stateStr": "SECONDARY"}]."ok": 1
}
Copy the code

That’s ok.

Replica set validation

  1. Verify data synchronization on slave nodes

Insert data on the primary node

rs:PRIMARY> db.col.insert({"name":"test"})
WriteResult({"nInserted" : 1})
rs:PRIMARY> db.col.find()
{"_id" : ObjectId("5f290145f350f0ccb3e03622"), "name" : "test" }
Copy the code

When you query data from a secondary node, a message is displayed indicating that data on a non-master node is unreadable. Set SlaveOk to make data readable.

rs:SECONDARY> db.col.find()
Error: error: {
        "operationTime" : Timestamp(1596522843, 1),
        "ok" : 0,
        "errmsg" : "not master and slaveOk=false",
        "code" : 13435,
        "codeName" : "NotMasterNoSlaveOk",
        "$clusterTime" : {
                "clusterTime" : Timestamp(1596522843, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
rs:SECONDARY> db.setSlaveOk()
rs:SECONDARY> db.col.find()
{"_id" : ObjectId("5f290145f350f0ccb3e03622"), "name" : "test" }
Copy the code
  1. Verify failover

Manually stop Mongo1 and enter mongo2 container to view node state. At this point, Mongo2 has been elected as the master node.

rs:PRIMARY> rs.status()
{
    "members": [{"_id": 1."name": "172.17.218.94:37017"."health": 0."state": 8."stateStr": "(not reachable/healthy)"."uptime": 0
        },
        {
            "_id": 2."name": "172.17.218.94:37018"."health": 1."state": 1."stateStr": "PRIMARY"
        },
        {
            "_id": 3."name": "172.17.218.94:37019"."health": 1."state": 2."stateStr": "SECONDARY"}}]Copy the code

Take it one step further: use Compose

Obviously, using Docker deployment configuration directly requires a lot of manual typing, which makes adapting to Compose much easier.

version: '3'
services:
  mongo-1:
    image: Mongo: 4.2.8
    hostname: mongo-1
    restart: always
    ports:
      - 37017: 27017
    volumes:
      - /home/mongodb/replset/mongo1/mongod.conf:/data/configdb/mongod.conf
      - /home/mongodb/replset/mongo1/data:/data/db
    command:
      - --config
      - /data/configdb/mongod.conf
  mongo-2:
    image: Mongo: 4.2.8
    hostname: mongo-2
    restart: always
    ports:
      - 37018: 27017
    volumes:
      - /home/mongodb/replset/mongo2/mongod.conf:/data/configdb/mongod.conf
      - /home/mongodb/replset/mongo2/data:/data/db
    command:
      - --config
      - /data/configdb/mongod.conf
  mongo-3:
    image: Mongo: 4.2.8
    hostname: mongo-3
    restart: always
    ports:
      - 37019: 27017
    volumes:
      - /home/mongodb/replset/mongo3/mongod.conf:/data/configdb/mongod.conf
      - /home/mongodb/replset/mongo3/data:/data/db
    command:
      - --config
      - /data/configdb/mongod.conf
  mongo-init:
    image: Mongo: 4.2.8
    depends_on:
      - mongo-1
      - mongo-2
      - mongo-3
    restart: on-failure:5
    command:
      - mongo
      - mongodb://@mongo-1:37017/admin
      - --eval
      - 'rs.initiate({_id:"rs", members: [{_id: 1, host: 172.17.218.94: "37017"}, {_id: 2, host: 172.17.218.94: "37018"}, {_id: 3, host: "172.17.218.94:37019",}]}); cfg = rs.conf(); cfg.members[0].priority=2; rs.reconfig(cfg)'
Copy the code

Based on the Docker command, the code for the replica set configuration is also written into the Compose configuration file, and mongo-1 is set as the primary node by default (priority=2).

Then, execute:

root@localhost:# docker-compose up -d
Copy the code

Once you enter Mongo-1, type rs.status() to see that the replica set is configured, out of the box.

Further configuration

  1. Creating a Database User

Enter mongo shell and execute the following command.

use admin
db.createUser({
  user: 'root',
  pwd: '123456',
  roles:[{
    role: 'root',
    db: 'admin'
  }]
})
Copy the code

Modify the configuration file to enable mandatory authentication

security:
   authorization: enabled
Copy the code

Restart the Mongod service. Docker may not be able to restart the Mongod service, directly modify the configuration file and restart the container.

Conf () will prompt “no authorization “, then execute db. Auth (“root”,”123456″) in admin database.

  1. Internode access control

For details about how to configure keyFile, see the official documentation.

conclusion

This paper introduces the content and construction method of MongoDB replica set in detail. Compared with a single point, replica sets can improve database availability and provide data redundancy, which is preferred in production environments. For more complex cases, read/write separation can be configured on a replica set basis. If a large amount of data cannot be stored at a single point, you can configure a fragmented cluster.

Appendix: Common commands

show dbs
show collections
show users
db.auth("root"."123456")
db.stats()
db.getUser("root")
rs.conf()
rs.status()
db.adminCommand({getParameter:"*"})
db._adminCommand({getCmdLineOpts: 1})
Copy the code

reference

  • Mongo – 4.2 – Manua – Replication
  • Deploy a Replica Set
  • Replica Set Deployment Architectures
  • Deploy Replica Set With Keyfile Authentication
  • MongoDB-4.2 Chinese documentation
  • Mongodb election mechanism
  • Docker deploys the MongoDB replica set
  • Docker-compose quickly builds mongodb replica sets