搭建一个简单的MongoDB副本集的过程

准备过程

服务器信息

三台服务器信息如下:

  • 系统版本: CentOS 7 7.6.1810
  • IP和主机信息:
    • mongodb_1 : 192.168.187.209
    • mongodb_2 : 192.168.187.210
    • mongodb_3 : 192.168.187.211
  • 安装MongoDB版本: 4.2

设置主机名

设置主机名, 根据预先的规划,分别登陆机器设置主机名字。

1
2
3
sudo hostnamectl set-hostname mongodb_1
sudo hostnamectl set-hostname mongodb_2
sudo hostnamectl set-hostname mongodb_3

设置主机名,添加如下信息到三台机器的/etc/hosts中。

1
2
3
4
5
sudo cat >> /etc/hosts << EOF
192.168.187.209 mongodb_1
192.168.187.210 mongodb_2
192.168.187.211 mongodb_3
EOF

SeLinux配置

如果要使用自定义的mongodb数据或日志路径,建议关闭SELinux。
在配置文件/etc/selinux/config中,将SELINUX=enforcing改为SELINUX=disabled
如果确定需要启动SeLinux, 并且需要使用自定义的数据路径,则可以参考官网设置。install-mongodb-on-red-hat/#configure-selinux

安装MongoDB

在三台服务器上分别安装MongoDB 4.2。完全4.2的安装步骤可参见官网Install MongoDB Community Edition on Red Hat or CentOS

三台服务器上,添加mongodb的yum源

1
2
3
4
5
6
7
8
9
sudo cat >> /etc/yum.repos.d/mongodb.repo << \EOF
[mongodb-org-4.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc
EOF

三台服务器上, 安装MongoDB

1
sudo yum install mongodb-org

三台服务器上,开启防火墙,允许27017端口访问

1
2
3
sudo firewall-cmd --add-service=mongodb --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

三台服务器上,在/opt目录下创建mongodb相关的目录

1
2
3
sudo mkdir -p /opt/mongodb/data
sudo mkdir -p /opt/mongodb/log
sudo chown -R mongod:mongod /opt/mongodb

三台服务器上,修改mongodb配置文件/etc/mongod.conf, 修改数据路径,日志路径和服务绑定IP等信息。

  • 数据路径: 设置storage.dbPath/opt/mongodb/data
  • 日志路径: 设置systemLog.path/opt/mongodb/log/mongod.log
  • 服务绑定IP: 设置net.bindIp为各个机器的内网地址,192.168.187.209,192.168.187.210192.168.187.211
  • 设置副本集名称: 设置replication.replSetNamereplicasetTest0replicasetTest0是副本集名称,可以根据实际进行修改,同一副本集所有实例,name需要一致。
  • 认证信息暂时先不设置,配置完集群设置的时候一起设置。

以服务器mongodb_1为例,此处的bindIp就应该是192.168.187.209, 对应的修改项如下。
设置之前先备份,永远是一个好习惯sudo cp /etc/mongod.conf /etc/mongod.conf.bak

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /opt/mongodb/log/mongod.log
# Where and how to store data.
storage:
dbPath: /opt/mongodb/data
journal:
enabled: true
# engine:
# wiredTiger:
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1,192.168.187.209 # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.
replication:
replSetName: replicasetTest0

三台服务器上,启动mongodb服务。

1
2
sudo systemctl enable mongod
sudo systemctl start mongod

配置Replicaset

建立集群

登录任意一台服务器的mongo, 执行如下命令配置副本集。

1
2
config = { _id:"replicasetTest0", members:[{_id:0,host:"192.168.187.209:27017" },{_id:1,host:"192.168.187.210:27017"},{_id:2,host:"192.168.187.211:27017"}]}
rs.initiate(config);

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ mongo
MongoDB shell version v4.2.14
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
---
> config = { _id:"replicasetTest0", members:[{_id:0,host:"192.168.187.209:27017" },{_id:1,host:"192.168.187.210:27017"},{_id:2,host:"192.168.187.211:27017"}]}
{
"_id" : "replicasetTest0",
"members" : [
{
"_id" : 0,
"host" : "192.168.187.209:27017"
},
{
"_id" : 1,
"host" : "192.168.187.210:27017"
},
{
"_id" : 2,
"host" : "192.168.187.211:27017"
}
]
}
> rs.initiate(config);
{ "ok" : 1 }
replicasetTest0:SECONDARY>

协商阶段,提示符会变成副本集名字:SECONDARY,协商结束后,Primary的机器的提示符会变成副本集名字:SECONDARY。在我们的例子中就是replicasetTest0:SECONDARYreplicasetTest0:PRIMARY

可以使用rs.status()来查看哪个服务器是PRIMARY,哪些服务器是SECONDARY

创建root用户

在启动认证之前,需要先创建登录用户。
PRIMARY节点上,执行mongo登录节点, 执行如下命令创建root用户。

1
2
3
4
5
6
7
$ use admin
$ db.createUser(
{
user: "my_root",
pwd: "mypassword",
roles: [ { role: "root", db: "admin" } ]
})

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
replicasetTest0:PRIMARY> use admin
switched to db admin
replicasetTest0:PRIMARY> db.createUser(
... {
... user: "my_root",
... pwd: "mypassword",
... roles: [ { role: "root", db: "admin" } ]
... })
Successfully added user: {
"user" : "my_root",
"roles" : [
{
"role" : "root",
"db" : "admin"
}
]
}
replicasetTest0:PRIMARY>

生成authKey

authKey用于实例认证,用于主从或者副本集直接验证,同副本集的文件内容需要一致
mongodb_1上生成keyFile.

1
2
3
4
sudo mkdir -p /etc/mongod/keyFiles/
sudo openssl rand -base64 756 > /etc/mongod/keyFiles/mongo-key
sudo chmod 400 /etc/mongod/keyFiles/mongo-key
sudo chown -R mongod:mongod /etc/mongod

mongodb_2mongodb_3上创建对应的目录和文件,将mongodb_1生成的key拷贝到mongodb_2mongodb_3上。

1
2
3
4
sudo mkdir -p /etc/mongod/keyFiles/
sudo echo "xxxxx" > /etc/mongod/keyFiles/mongo-key
sudo chmod 400 /etc/mongod/keyFiles/mongo-key
sudo chown -R mongod:mongod /etc/mongod

启用集群服务器的认证功能

三台服务器中启用认证功能。在/etc/mongod.conf中设置keyFileauthorization

  • 开启认证: 设置security.authorizationenabled,启动登录认证。
  • 配置认证key文件,设置security.keyFile为上个步骤设置的文件/etc/mongod/keyFiles/mongo-key.
1
2
3
security:
authorization: enabled
keyFile: /etc/mongod/keyFiles/mongo-key # 配置keyfile文件

配置过后,sudo systemctl restart mongod重启三台服务器。

验证是否启用了账号登录。

1
2
3
$ mongo
replicasetTest0:PRIMARY> use admin
replicasetTest0:PRIMARY> db.auth("my_root", "mypassword")

数据测试

此时,集群状态:mongodb_1为PRIMARY,mongodb_2mongodb_3为SECONDARY。

  1. 登录Primary数据库,插入如下数据
    执行mongo mongodb://my_root:mypassword@mongodb_1:27017登录Primary数据库。

    1
    2
    3
    4
    5
    6
    7
    use replicatestdata
    db.createCollection("replicatestCollection01")
    db.replicatestCollection01.insertMany([
    {name: "test_record_one", description: "testing replica set", record: 1},
    {name: "test_record_two", description: "testing replica set", record: 2},
    {name: "test_record_three", description: "testing replica set", record: 3}
    ])
  2. mongodb_2上查看数据
    执行mongo mongodb://my_root:mypassword@mongodb_2:27017登录mongodb_2数据库。

    1
    2
    3
    4
    5
    6
    7
    8
    replicasetTest0:SECONDARY> db.getMongo().setSecondaryOk();
    replicasetTest0:SECONDARY> use replicatestdata
    switched to db replicatestdata
    replicasetTest0:SECONDARY> db.replicatestCollection01.find()
    { "_id" : ObjectId("60ec094a7f37fee5e1bc1980"), "name" : "test_record_one", "description" : "testing replica set", "record" : 1 }
    { "_id" : ObjectId("60ec094a7f37fee5e1bc1981"), "name" : "test_record_two", "description" : "testing replica set", "record" : 2 }
    { "_id" : ObjectId("60ec094a7f37fee5e1bc1982"), "name" : "test_record_three", "description" : "testing replica set", "record" : 3 }
    replicasetTest0:SECONDARY>
  3. mongodb_3上查看数据
    执行mongo mongodb://my_root:mypassword@mongodb_3:27017登录mongodb_3数据库。

    1
    2
    3
    4
    5
    6
    7
    8
    replicasetTest0:SECONDARY> db.getMongo().setSecondaryOk();
    replicasetTest0:SECONDARY> use replicatestdata
    switched to db replicatestdata
    replicasetTest0:SECONDARY> db.replicatestCollection01.find()
    { "_id" : ObjectId("60ec094a7f37fee5e1bc1980"), "name" : "test_record_one", "description" : "testing replica set", "record" : 1 }
    { "_id" : ObjectId("60ec094a7f37fee5e1bc1982"), "name" : "test_record_three", "description" : "testing replica set", "record" : 3 }
    { "_id" : ObjectId("60ec094a7f37fee5e1bc1981"), "name" : "test_record_two", "description" : "testing replica set", "record" : 2 }
    replicasetTest0:SECONDARY>

可以看到在PRIMARY mongodb_1中的数据,被复制到了mongodb_2mongodb_3中。

一些Tips

启动mongod,报 ExecStart=/usr/bin/mongod $OPTIONS (code=exited, status=1/FAILURE)

stauts=1, 一般是文件权限问题,除了常规的用户组权限以外,如果CentOS开启了SELinux,注意还需要进行SELinux权限设置。参见官网文档install-mongodb-on-red-hat/#configure-selinux

集群配置

集群配置中,可以通过priority设置节点的优先级,还可以通过votes字段来设置节点是否加入投票。
例子:

1
2
config = { _id:"rs", members:[{_id:0,host:"192.168.83.131:27017", priority : 100, votes: 1 },{_id:1,host:"192.168.83.33:27017", priority : 0, votes: 0}]}
rs.initiate(config);

SECONDARY上开启查询

默认情况下,不能直接使用mongo命令在SECONDARY的节点上进行查询。如果要查询,需要先执行db.getMongo().setSecondaryOk();打开查询功能,然后再查询。

集群命令

  • rs.status(): 查看集群状态
  • rs.conf(): 查看集群配置
  • rs.add(): 添加集群节点
  • rs.initiate(cfg): 使用配置信息初始化集群
    • cfg例子: config = { _id:"rs", members:[{_id:0,host:"192.168.83.131:27017", priority : 100, votes: 1 },{_id:1,host:"192.168.83.33:27017", priority : 0, votes: 0}]}
  • rs.reconfig(cfg): 指定配置信息重置副本集;指定第二个参数{force:true},来强制更新
    • 例子: 剔除mongodb_3的节点,重置为两个节点: rs.reconfig({ _id:"replicasetTest0", members:[{_id:0,host:"192.168.187.209:27017" },{_id:1,host:"192.168.187.210:27017"}]})
  • rs.add(membercfgobj): 使用指定配置,给副本集添加新成员
    • 例子: 重新添加mongodb_3节点。rs.add( { host: "192.168.187.211:27017", priority: 1, votes: 1 } )
  • rs.remove(hostportstr): 从副本集删除指定节点
    • 例子: 删除mongodb_3节点。 rs.remove("192.168.187.211:27017")
  • rs.printReplicationInfo(): 查看操作日志以及日志时间
  • rs.printSecondaryReplicationInfo(): 查看各个SECONDARY节点和PRIMARY之间的延迟情况

Reference

留言