MongoDB 复制集(Replica Set)搭建

通常,为了防止单点故障应用程序需要做集群。然而在数据库中除了防止单点故障,还需要做到数据库备份,读写分离,故障转移等。而 MongoDB 的 Replica Set 恰恰都能满足这些要求。

复制集成员

Replica Set 的成员是一堆有着同样的数据内容 mongod 的实例集合,包含以下三类角色:

  1. 主节点(Primary)
    是 Replica Set 中唯一的接收写请求的节点,并将写入指令记录到 oplog 上。副本节点通过复制 oplog 的写入指令同步主节点的数据。Secondary。一个 Replica Set 有且只有Primary 节点,当Primar挂掉后,其他 Secondary 或者 Arbiter 节点会重新选举出来一个主节点。应用程序的默认读取请求也是发到 Primary节点处理的。

  2. 副本节点(Secondary)
    通过复制主节点 oplog 中的指令与主节点保持同样的数据集,当主节点挂掉的时候,参与主节点选举。

  3. 仲裁者(Arbiter)
    不存储实际应用数据,只投票参与选取主节点,但不会被选举成为主节点。

复制集搭建(3个成员)

  1. 节点目录结构说明

    《MongoDB 复制集(Replica Set)搭建》 节点目录结构

    其中,instance 、instance_1、instance_2 分别代表3个节点。每个节点都有相同的目录结构,包含了数据目录 data ,日志目录 logs , JavaScript 文件目录 js, 启停脚本 mongod-server.sh,节点配置文件 mongod.conf 等

  2. 节点配置文件 mongod.conf

# syslog配置
logpath=/mnt/mongodb/instance/logs/mongod.log #日志目录
logappend=true
timeStampFormat=iso8601-utc
# storage 存储配置
dbpath=/mnt/mongodb/instance/data/db #数据存储目录
directoryperdb=true
# processManagement 进程管理配置
fork=true
pidfilepath=/mnt/mongodb/instance/var/run/mongod.pid # 进程 PID 文件保存目录
# net 网络配置
bind_ip=127.0.0.1
port=27017 
# security 配置
#auth=true
# 复制集
replSet=test-set    # 复制集 name         

其中 logpath 、dbpath、 pidfilepath 需要根据节点修改到对应目录(路径中的instance 改为 instance_1或 instance_2)。此外还需要修改每个节点的 port,在我的配置当中,instance 、instance_1、instance_2 的端口分别为 27017、27018、27019。

  1. 启动三个节点
    这里启动需要用到上面提到的 mongod-server.sh 服务启停脚本(这个脚本是我自己编写的用于管理 mongod 进程启停,详细了解猛戳这里
    分别在 instance、instance_1、 instance_2 目录中执行一下命令./mongod-server.sh start
[root@iZu1qhttxe5Z instance]# ls
data  dump  js  logs  mongod.conf  mongod-server.sh  var
[root@iZu1qhttxe5Z instance]# ./mongod-server.sh start
about to fork child process, waiting until server is ready for connections.
forked process: 680
child process started successfully, parent exiting
Started [680]
[root@iZu1qhttxe5Z instance]# 

这个时候3个节点已经启动了,接下来需要初始化复制集。

  1. 初始化复制集
    选择任意的节点,进入 js 目录:
[root@iZu1qhttxe5Z js]$ ls
initiate_rs.js  user.js
[root@iZu1qhttxe5Z js]# cat initiate_rs.js 
rs.initiate()
rs.add("iZu1qhttxe5Z:27017")
rs.add("iZu1qhttxe5Z:27019")
rs.conf()
[root@iZu1qhttxe5Z js]# 

这里的 initiate_rs.js 文件适用于初始化复制集的js文件,其实这些操作可以在 mongo shell中操作,但是为了方便运维管理,所以将此操作提取到 js 文件(如何将 mongo shell 命令提出到 js 文件猛戳这里)。

执行初始化,这里选取端口 27018 的节点。

[root@iZu1qhttxe5Z instance_1]# mongo --port 27018 ./js/initiate_rs.js 
MongoDB shell version v3.4.5
connecting to: mongodb://127.0.0.1:27018/
MongoDB server version: 3.4.5
[root@iZu1qhttxe5Z instance_1]# 

连接到其中一个节点,查看是否初始化成功

test-set:SECONDARY> rs.status()
{
    "set" : "test-set",
    "date" : ISODate("2017-06-28T02:57:33.424Z"),
    ......
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "10.117.225.127:27018",
            ...........
            "stateStr" : "SECONDARY",
            ...........
        },
        {
            "_id" : 1,
            "name" : "iZu1qhttxe5Z:27017",
            .............
            "stateStr" : "PRIMARY",
            ..............
        },
        {
            "_id" : 2,
            "name" : "iZu1qhttxe5Z:27019",
            .........
            "stateStr" : "SECONDARY",
            .........
        }
    ],
    "ok" : 1
}
test-set:SECONDARY> 

可以看出复制集已经初始化成功。

  1. 连接Primary节点,写入数据。
test-set:PRIMARY> use test
switched to db test
test-set:PRIMARY> show collections
test-set:PRIMARY> db.test.insert({"name":"knight"});
WriteResult({ "nInserted" : 1 })
test-set:PRIMARY> show collections
test
test-set:PRIMARY> db.test.find()
{ "_id" : ObjectId("59531cd6000e29eae22a2f83"), "name" : "knight" }
test-set:PRIMARY> 

数据插入成功,验证 SECONDARY 是否同步数据

# 27018 节点
[root@iZu1qhttxe5Z js]# mongo --port 27018
MongoDB shell version v3.4.5
connecting to: mongodb://127.0.0.1:27018/
MongoDB server version: 3.4.5
....
test-set:SECONDARY>
test-set:SECONDARY> rs.slaveOk()
test-set:SECONDARY> use test
switched to db test
test-set:SECONDARY> show collections
test
test-set:SECONDARY> db.test.find()
{ "_id" : ObjectId("59531cd6000e29eae22a2f83"), "name" : "knight" }
test-set:SECONDARY> 
[root@iZu1qhttxe5Z js]#
[root@iZu1qhttxe5Z js]#
[root@iZu1qhttxe5Z js]#
# 27019 节点
[root@iZu1qhttxe5Z js]# mongo --port 27019
MongoDB shell version v3.4.5
connecting to: mongodb://127.0.0.1:27019/
MongoDB server version: 3.4.5
....
test-set:SECONDARY> rs.slaveOk()
test-set:SECONDARY> use test
switched to db test
test-set:SECONDARY> db.test.find()
{ "_id" : ObjectId("59531cd6000e29eae22a2f83"), "name" : "knight" }
test-set:SECONDARY> 
  1. 默认情况下,Secondary不能读和写, 需要执行 rs.slaveOk()(或者执行db.getMongo().setSlaveOk())。
test-set:SECONDARY> use test
switched to db test
test-set:SECONDARY> db.test.find()
Error: error: {
    "ok" : 0,
    "errmsg" : "not master and slaveOk=false",
    "code" : 13435,
    "codeName" : "NotMasterNoSlaveOk"
}
test-set:SECONDARY> 

References:

MongoDB 执行 js 文件
MongoDB 启停脚本

    原文作者:非典型程序员
    原文地址: https://www.jianshu.com/p/ac31be1fef1f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞