一 MongoDB 复制(副本集)
1.1 复制概述
MongoDB复制是将数据同步在多个服务器的过程。
复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提升了数据的可用性, 并能够保证数据的安全性。
复制还容许从硬件故障和服务中断中恢复数据。
1.2 复制意义
- 保障数据的安全性
- 数据高可用性 (24*7)
- 灾难恢复
- 无需停机维护(如备份,重建索引,压缩)
- 分布式读取数据
注意:副本集不是为了提升读性能存在的,在进行oplog的时候,读操做是被阻塞的;
提升读取性能应该使用分片和索引,它的存在更可能是做为数据冗余,备份;
尤为当主库原本就面临着大量的写入压力,对于副本集的节点,也一样会面临写的压力。
1.3 MongoDB复制原理
mongodb的复制至少须要两个节点。其中一个是主节点,负责处理客户端请求,其他的都是从节点,负责复制主节点上的数据。
mongodb各个节点常见的搭配方式为:一主一从、一主多从。
主节点记录在其上的全部操做oplog,从节点按期轮询主节点获取这些操做,而后对本身的数据副本执行这些操做,从而保证从节点的数据与主节点一致。
MongoDB复制结构图以下所示:
添加Heartbeat监控副本之间的心跳架构:
设置一个仲裁节点架构:
说明:客户端从主节点读取数据,在客户端写入数据到主节点时, 主节点与从节点进行数据交互保障数据的一致性。
1.4 MongoDB复制过程
Primary节点写入数据,Secondary经过读取Primary的oplog获得复制信息,开始复制数据而且将复制信息写入到本身的oplog。若是某个操做失败,则备份节点中止从当前数据源复制数据。若是某个备份节点因为某些缘由挂掉了,当从新启动后,就会自动从oplog的最后一个操做开始同步。同步完成后,将信息写入本身的oplog,因为复制操做是先复制数据,复制完成后再写入oplog,有可能相同的操做会同步两份,不过MongoDB在设计之初就考虑到这个问题,将oplog的同一个操做执行屡次,与执行一次的效果是同样的。
当Primary节点完成数据操做后,Secondary的数据同步过程以下:
-
检查本身local库的oplog.rs集合找出最近的时间戳。
- 检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录。
- 将找到的记录插入到本身的oplog.rs集合中,并执行这些操做。
副本集的同步和主从同步同样,都是异步同步的过程,不一样的是副本集有个自动故障转移的功能。其原理是:slave端从primary端获取日志,而后在本身身上彻底顺序的执行日志所记录的各类操做(该日志是不记录查询操做的),这个日志就是local数据库中的oplog.rs表,默认在64位机器上这个表是比较大的,占磁盘大小的5%,oplog.rs的大小能够在启动参数中设 定:--oplogSize 1000,单位是M。
注意:在副本集的环境中,要是全部的Secondary都宕机了,只剩下Primary。最后Primary会变成Secondary,不能提供服务。
1.5 副本集
副本集特征:
- N 个节点的集群;
- 任何节点可做为主节点;
- 全部写入操做都在主节点上;
- 自动故障转移;
- 自动恢复。
集群中没有特定的主库,主库是选举产生,若是主库down了,会再选举出一台主库。
mongoDB也能够配置成主从模式,但官方已经不建议使用主从模式了,替代方案是采用副本集的模式。
副本集有如下特色:
- 最小构成是:primary,secondary,arbiter,通常部署是:primary,2 secondary。
- 成员数应该为奇数,若是为偶数的状况下添加arbiter,arbiter不保存数据,只投票。
- 最大50 members,可是只能有 7 voting members,其余是non-voting members。
注意:在副本集的环境中,若是全部的Secondary都宕机了,只剩下Primary。最后Primary会变成Secondary,且不能提供服务。
二 前期准备
-
NTP同步;
- 关闭SELinux;
- 关闭防火墙或放通相应规则;
- 全部节点安装MongoDB,参考《002.MongoDB社区版安装》;
节点规划:
主机名
|
IP
|
类型
|
备注
|
mongodb01
|
172.24.8.71
|
primary
|
主节点
|
mongodb02
|
172.24.8.72
|
secondary
|
此节点
|
mongodb03
|
172.24.8.73
|
secondary
|
此节点
|
mongodb04
|
172.24.8.74
|
secondary
|
备节点(测试手动添加)
|
arbiter
|
172.24.8.75
|
arbiter
|
冲裁节点
|
追加解析:
1 [root@mongodb01 ~]# vi /etc/hosts
2 172.24.8.71 mongodb01
3 172.24.8.72 mongodb02
4 172.24.8.73 mongodb03
5 172.24.8.74 mongodb04
6 172.24.8.75 arbite
提示:全部节点均建议添加以上解析。
三 副本集正式部署
3.1 开启远程链接及副本集
1 [root@mongodb01 ~]# vi /etc/mongod.conf
2 ……
3 net:
4 port: 27017
5 bindIp: 172.24.8.71 #根据不一样节点配置
6 ……
7 replication:
8 replSetName: my_rep #开启副本集,全部节点必须一致
9 ……
10 [root@mongodb01 ~]# systemctl start mongod.service
11 [root@mongodb01 ~]# systemctl enable mongod.service
注意:在完成复制集初始化、新建用户等操做以前必须保持security.authorization:enabled为注释状态。
3.2 配置复制级成员
1 [root@mongodb01 ~]# mongo --host 172.24.8.71
2 > config = { _id: "my_rep", members: [
3 {_id: 0, host: "172.24.8.71:27017"},
4 {_id: 1, host: "172.24.8.72:27017"},
5 {_id: 2, host: "172.24.8.73:27017"}]
6 }
参数解释:
"_id": 副本集的名称
"members": 副本集的服务器列表
"_id": 服务器的惟一ID
"host": 服务器主机
"priority": 是优先级,默认为1,优先级0为被动节点,不能成为活跃节点。优先级不为0则按照有大到小选出活跃节点。
"arbiterOnly": 仲裁节点,只参与投票,不接收数据,也不能成为活跃节点。
3.3 初始化副本集
1 > rs.initiate(config)
2 my_rep1:PRIMARY> rs.status() #查看集群状态
3.4 建立管理员用户
1 [root@mongodb01 ~]# mongo --host 172.24.8.71
2 my_rep:PRIMARY> use admin #进入admin数据库
3 my_rep:PRIMARY> db.createUser({ user: "admin", pwd: "admin", roles: [{ role: "userAdminAnyDatabase", db: "admin" }] })
4 my_rep:PRIMARY> db.auth("admin", "admin") #验证建立结果
5 1
提示:以上为建议项,建议建立一个管理员用于内部管理MongoDB。
mongodb中的用户是基于身份role的,该管理员帐户的 role是 userAdminAnyDatabase。 ‘userAdmin’表明用户管理身份,’AnyDatabase’ 表明能够管理任何数据库。
db.auth()能够验证 用户。
1 my_rep:PRIMARY> db.getUsers()
2 > db.system.users.find().pretty() #查看全局全部帐户
提示:mongo shell 可经过.pretty() 对输出进行JSON格式化,以便提升输出的可读性。
3.5 建立集群用户
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u admin -p admin
2 my_rep1:PRIMARY> use admin
3 switched to db admin
4 my_rep1:PRIMARY> db.createUser({user:"clusteradmin",pwd:"clusteradmin",roles:[{role:"clusterAdmin",db:"admin"}]})
提示:3.2——3.5仅需在集群任何一台节点操做便可。
3.6 确认验证
1 [root@mongodb01 ~]# mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin
2 my_rep:SECONDARY> rs.status()
3 my_rep:SECONDARY> db.serverStatus().repl.primary #查看主节点
4 172.24.8.73:27017
四 集群开启权限
建议使用keyfile访问控制的方式创建各个节点间的安全认证机制。
4.1 配置key
1 [root@mongodb01 ~]# mkdir -p /usr/local/keyfile
2 [root@mongodb01 ~]# openssl rand -base64 100 > /usr/local/keyfile/mongodb_keyfile
3 [root@mongodb01 ~]# chmod 600 /usr/local/keyfile/mongodb_keyfile
4 [root@mongodb01 ~]# chown -R mongod:mongod /usr/local/keyfile/
5 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@mongodb02:/usr/local/
6 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@mongodb03:/usr/local/
7 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@mongodb04:/usr/local/
8 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@arbiter:/usr/local/
9
10 [root@mongodb02 ~]# chown -R mongod:mongod /usr/local/keyfile/
11 [root@mongodb03 ~]# chown -R mongod:mongod /usr/local/keyfile/
12 [root@mongodb04 ~]# chown -R mongod:mongod /usr/local/keyfile/
13 [root@arbiter~]# chown -R mongod:mongod /usr/local/keyfile/
4.2 开启权限
1 [root@mongodb01 ~]# vi /etc/mongod.conf
2 ……
3 security: #取消注释
4 authorization: enabled #开启验证
5 keyFile: /usr/local/keyfile/mongodb_keyfile #key文件
6 ……
7 [root@mongodb01 ~]# systemctl restart mongod.service
提示:须要在全部节点进行开启操做。
4.3 测试登录
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
2 my_rep:PRIMARY> rs.status()
3 my_rep:PRIMARY> db.serverStatus().repl.primary #查看主节点
4 172.24.8.71:27017
五 成员管理
5.1 SECONDARY节点增长
1 [root@mongodb01 ~]# scp -rp /etc/mongod.conf root@mongodb04:/etc/mongod.conf
2 [root@mongodb04 ~]# vi /etc/mongod.conf #修改IP便可
3 net:
4 port: 27017
5 bindIp: 172.24.8.74
6 [root@mongodb04 ~]# systemctl restart mongod.service
7 [root@mongodb04 ~]# systemctl enable mongod.service
8 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
9 my_rep:PRIMARY> rs.add("172.24.8.74:27017")
5.2 节点删除
1 my_rep:PRIMARY> rs.remove("172.24.8.74:27017")
提示:修改副本集成员配置时的限制:
- 不能修改_id;
- 不能将当前执行rs.reconfig命令的成员的优先级设置为 0;
- 不能将仲裁者成员变为非仲裁者成员,反正亦然;
- 不能将buildIndexes由false改成 true。
5.3 Secondary开放临时读
默认状况下,Secondary是不提供服务的,即不能读和写。在特殊状况下须要读的可执行rs.slaveOk() ,只对当前链接有效。
5.4 节点提权
默认全部的节点priority都为1,自动选举primary,可经过如下方式手动在已运行的副本集中指定primary。
注意:如下方式更换主节点必须在当前primary节点操做。
1 my_rep:SECONDARY> db.serverStatus().repl.primary #查看主节点
2 172.24.8.72:27017
3 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin
4 my_rep:PRIMARY> rs.status() #查看当前副本集状态
1 my_rep:PRIMARY> rs.conf()
1 my_rep:PRIMARY> newcfg=rs.conf() #当前conf写入变量
2 my_rep:PRIMARY> newcfg.members[0].priority=2 #修改conf中members序号0,即172.24.8.71优先级为2
3 2
4 my_rep:PRIMARY> rs.reconfig(newcfg #从新载入conf
5 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
6 my_rep:PRIMARY> db.serverStatus().repl.primary #再次登陆查看primary节点
7 172.24.8.71:27017
5.5 ARBITER节点添加
1 [root@mongodb01 ~]# scp -rp /etc/mongod.conf root@arbiter:/etc/mongod.conf
2 [root@mongodb04 ~]# vi /etc/mongod.conf #修改IP便可
3 net:
4 port: 27017
5 bindIp: 172.24.8.75
6 [root@mongodb04 ~]# systemctl restart mongod.service
7 [root@mongodb04 ~]# systemctl enable mongod.service
8 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
9 my_rep:PRIMARY> rs.addArb("172.24.8.75:27017")
10 my_rep:PRIMARY> rs.status()
1 my_rep:PRIMARY> rs.conf()
提示:副本集要求参与选举投票(vote)的节点数为奇数,当咱们实际环境中由于机器等缘由限制只有两个(或偶数)的节点,这时为了实现 Automatic Failover引入另外一类节点:仲裁者(arbiter),仲裁者只参与投票不拥有实际的数据,而且不提供任何服务,所以它对物理资源要求不严格。
5.6 修改为员状态
1 my_rep:PRIMARY> rs.stepDown()
提示:rs.stepDown(60)表示让主节点退化为备份节点,并维持60秒。若是60s内没有新的主节点被选举出来,那么当前节点能够要求从新参与进行选举。
5.7 锁定主节点
将全部的备份节点的priority和votes都设置为0,这样只有主节点有投票权因此不管备份节点是否存在都不会致使主节点的状态由primary变成other。
1 my_rep:PRIMARY> newconf=rs.config()
2 my_rep:PRIMARY> newconf.members[1].priority=0
3 my_rep:PRIMARY> newconf.members[1].votes=0
4 my_rep:PRIMARY> rs.reconfig(newconf)
5.8 阻止成员选举
若是须要对主节点进行维护操做,可是不但愿这段时间内其它成员选举为主节点,能够在每一个备份节点上执行freeze命令,以强制它们始终处于备份节点的状态。命令以秒为单位。
1 my_rep:SECONDARY> rs.freeze(3600) #保持1个小时处于备份节点状态。
2 my_rep:SECONDARY> rs.freeze(0) #再次在备份节点执行且将时间指定为0就是“释放”备份节点。
注意:若是在退位的备份节点上执行rs.freeze(0),可让退位的备份节点从新变为主节点。
六 副本集管理
6.1 查看复制状况
1 my_rep:PRIMARY> db.printSlaveReplicationInfo()
2 source: 172.24.8.72:27017
3 syncedTo: Tue May 28 2019 19:43:40 GMT+0800 (CST)
4 0 secs (0 hrs) behind the primary
5 source: 172.24.8.73:27017
6 syncedTo: Tue May 28 2019 19:43:40 GMT+0800 (CST)
7 0 secs (0 hrs) behind the primary
解释:
source:从库的ip和端口。
syncedTo:目前的同步状况,以及最后一次同步的时间。
在数据库内容不变的状况下是不一样步的,数据库变更就会立刻同步。
6.2 副本集复制链配置
MongoDB根据ping时间选择同步源,一个成员向另外一个成员发送心跳请求,获取心跳请求所耗费的时间(rs.status()中的"pingMs"记录了成员到达相关成员的所花费的平均时间)。
MongosDB维护着不一样成员间请求的平均花费时间。选择同步源时,会选择一个离本身比较近并且数据比本身新的成员。可是同一数据中心的成员可能会从同一数据中心的其余成员处复制,而不是从位于另外一个数据中心的主节点处复制(这样能够减小网络流量),因此会出现复制链的状况,复制链越长会致使主节点的操做复制到全部的服务器所花费的时间越长,从而影响必定的性能。
1 [root@mongodb03 ~]# mongo --host 172.24.8.73 -u clusteradmin -p clusteradmin
2 my_rep:SECONDARY> db.adminCommand({"replSetGetStatus":1})['syncingTo']; #查看备份节点的复制源
3 172.24.8.71:27017
4 my_rep:SECONDARY> db.adminCommand({"replSetSyncFrom":"172.24.8.72:27017"}) #配置复制源
6.3 查看副本集状态
1 my_rep:PRIMARY> rs.status()
6.4 查看副本集配置
1 my_rep:PRIMARY> rs.conf() #查看节点配置
6.5 强制从新配置副本集
若是副本集没法选出新的主节点,这时须要从新配置副本集。能够在备份节点上调用rs.reconfig(conf,{"force":ture})强制从新配置副本集。
备份节点收到新的配置文件以后,就会修改自身的配置,而且将新的配置发送给副本集中的其余成员。副本集的其余成员收到新的配置文件以后,会判断配置文件的发送者是不是它们当前配置中的一个成员,若是是,才会用新的配置文件对本身进行从新配置。
因此,若是新的配置修改了某些成员的主机名,则应该关闭被修改主机名的节点,并以单机模式启动,手动修改locak.system.replset文档,而后以副本集的方式从新启动。
注意:conf必须是正确、有效的配置。并且强制从新配置只容许在备份节点执行。
6.6 查看副本集log状态
1 my_rep:PRIMARY> rs.printReplicationInfo()
2 configured oplog size: 1194.595947265625MB
3 log length start to end: 14027secs (3.9hrs)
4 oplog first event time: Tue May 28 2019 17:21:54 GMT+0800 (CST)
5 oplog last event time: Tue May 28 2019 21:15:41 GMT+0800 (CST)
6 now: Tue May 28 2019 21:15:48 GMT+0800 (CST)
解释:
configured oplog size:oplog配置的大小
log length start to end:oplog包含的操做时长。
oplog first event time:oplog第一条操做的时间。
oplog last event time:oplog最后一条操做的时间。
now:当前时间。
注意:oplog中第一条操做与最后一条操做的时间差就是操做日志的长度。
6.7 查看复制延时
1 my_rep:PRIMARY> rs.printSlaveReplicationInfo()
2 source: 172.24.8.72:27017
3 syncedTo: Tue May 28 2019 21:17:40 GMT+0800 (CST)
4 0 secs (0 hrs) behind the primary
5 source: 172.24.8.73:27017
6 syncedTo: Tue May 28 2019 21:17:40 GMT+0800 (CST)
7 0 secs (0 hrs) behind the primary
8 source: 172.24.8.74:27017
9 syncedTo: Tue May 28 2019 21:17:40 GMT+0800 (CST)
10 0 secs (0 hrs) behind the primary
6.8 副本集信息查看(监控)命令汇总
1.复制集状态查询:rs.status()
2.查看当前副本集oplog状态:rs.printReplicationInfo()
3.查看复制延迟:rs.printSlaveReplicationInfo()
4.查看服务状态详情:db.serverStatus()
5.查询副本集配置:rs.conf()
6.主副本查询:db.isMaster()
6.9 其余常见维护命令
经过rs.help()命令,能够查看副本集相关操做命令:
1 replSetHO:PRIMARY> rs.help()
2 rs.status() #查看副本集总体健康状态
3 rs.initiate() #使用默认配置初始化副本集
4 rs.initiate(cfg) #使用指定配置,初始化副本集;这是咱们使用的命令
5 rs.conf() #从local.system.replset获取副本集当前配置信息
6 rs.reconfig(cfg) #指定配置信息重置副本集;指定第二个参数{force:true},来强制更新
7 rs.add(hostportstr) #使用默认配置,给副本集添加新成员
8 rs.add(membercfgobj) #使用指定配置,给副本集添加新成员
9 rs.addArb(hostportstr) #给副本集添加一个仲裁节点,只投票,不会成为数据节点
10 rs.stepDown([stepdownSecs, catchUpSecs]) #给PRIMARY降权,使之在指定时间内成为SECONDARY,会恢复
11 rs.syncFrom(hostportstr) #使SECONDARY从指定的服务器同步数据
12 rs.freeze(secs) #让本身在指定秒数内不会成为PRIMARY
13 rs.remove(hostportstr) #从副本集删除指定节点
14 rs.slaveOk() #SECONDARY节点默认是不能查询的,须要执行该命令,使之能够查询
15 rs.printReplicationInfo() #查看操做日志以及日志时间
16 rs.printSlaveReplicationInfo() #查看全部SECONDARY延迟状况
17 db.isMaster() #查询当前PRIMARY信息
提示:更多副本集选举参考官方:https://docs.mongodb.com/manual/core/replica-set-elections/。
七 副本集复制功能测试
7.1 受权
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u admin -p admin
2 my_rep:PRIMARY> use admin
3 my_rep:PRIMARY> db.grantRolesToUser( "admin",[{ role: "dbOwner",db:"mydb" }])
7.2 插入数据
1 my_rep:PRIMARY> use mydb
2 my_rep:PRIMARY> db.age01.insert({name: 'zhangsan',
3 age: '18',
4 tel: '123456781',
5 love: ['apple','banana']
6 }
7.3 查看同步
1 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u admin -p admin
2 my_rep:SECONDARY> rs.slaveOk()
3 my_rep:SECONDARY> use mydb
4 my_rep:SECONDARY> db.age01.count()
5 1
八 副本集故障转移功能测试
8.1 关闭主节点
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
2 my_rep:PRIMARY> rs.status()
3 my_rep:PRIMARY> use admin
4 switched to db admin
5 my_rep:PRIMARY> db.shutdownServer()
6 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin #登陆任意非关闭节点
7 my_rep:PRIMARY> rs.status()
8 my_rep:PRIMARY> db.serverStatus().repl.primary #查看主节点
9 172.24.8.72:27017
8.2 插入数据
1 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u admin -p admin
2 my_rep:PRIMARY> use mydb
3 db.age01.insertOne({name: 'wanger', age: '15', tel: '123456783', love: ['pear','orange']})
8.3 开启关闭节点
1 [root@mongodb01 ~]# systemctl restart mongod.service
2 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u admin -p admin
3 my_rep:SECONDARY> use mydb
4 switched to db mydb
5 my_rep:SECONDARY> rs.slaveOk()
6 my_rep:SECONDARY> db.age01.find().pretty()
提示:当关闭节点mongo服务重启启动后,能正常以SECONDARY加入副本集,而且自动同步相关数据。
注意:全部的Secondary都宕机、或则副本集中只剩下一个节点,则该节点只能为Secondary节点,也就意味着整个集群只能进行读操做而不能进行写操做,当其余节点恢复时,以前的primary节点仍然是primary节点。
当某个节点宕机后从新启动该节点会有一段的时间(时间长短视集群的数据量和宕机时间而定)致使整个集群中全部节点都成为secondary而没法进行写操做(若是应用程序没有设置相应的ReadReference也可能不能进行读取操做)。
官方推荐的最小的副本集也应该具有一个primary节点和两个secondary节点。两个节点的副本集不具有真正的故障转移能力。
参考:https://www.cnblogs.com/zhoujinyi/p/3554010.html
https://www.cnblogs.com/chenmh/p/8681867.html