MongoDB–副本集的简单操作和选举
文章目录
一:一些简单的操作
db.isMaster()可以查看副本集的状态
cqsm>db.isMaster()
{
"hosts" : [
"192.168.2.101:27017",
"192.168.2.102:27017",
"192.168.2.103:27017"
],
"setName" : "cqsm1",
"setVersion" : 1,
"ismaster" : true,
"secondary" : false,
"primary" : "192.168.2.101:27017",
"me" : "192.168.2.101:27017",
"electionId" : ObjectId("7fffffff0000000000000002"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1575438803, 1),
"t" : NumberLong(2)
},
"lastWriteDate" : ISODate("2019-12-04T05:53:23Z"),
"majorityOpTime" : {
"ts" : Timestamp(1575438803, 1),
"t" : NumberLong(2)
},
"majorityWriteDate" : ISODate("2019-12-04T05:53:23Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2019-12-04T05:53:32.170Z"),
"logicalSessionTimeoutMinutes" : 30,
"minWireVersion" : 0,
"maxWireVersion" : 6,
"readOnly" : false,
"ok" : 1,
"operationTime" : Timestamp(1575438803, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1575438803, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
向主节点写入数据:
cqsm>for(i=0;i<100;i++){db.mongo.insert({count:i})}
WriteResult({ "nInserted" : 1 })
去副节点读写入的数据:由于备份节点的数据可能并没有很快的和主节点同步,为了防止用户拿到不一致或者过期的数据,备份节点上拒绝做查询。可以在数据存储的数据库上使用db.setSlaveOk(),之后就可以做查询了。
>use cqsm
>db.setSlaveOk()
>db.mongo.find()
二:故障转移和选举机制
如果主节点挂掉了,其中一个备份节点会自动选举成为主节点。成为主节点之后就可以接受读写了。这里发了一个选举的过程,选举的前提是副本集中大多数成员给某一个节点投票,所以副本集一定要满足“大多数”。当一个副本集中,一个主节点没有得到大多数的支持,也会退位为普通结点。
大多数原则:存活主机小于总主机数的1/2 就不会发生选举,这里的存活的意思是可以互相通信的节点个数。
上图共有7个节点,DC1有4个节点并且主节点在DC1,而DC2有三个节点都是从节点。由于在两个机房之间的网络通信有很多不确定性,并且复制集节点之间主要靠心跳信息来确认对方是否存活是否重新选举,默认心跳信息从节点2秒传送一次给主节点,如果在10秒内对方没有回应那么就认为主节点故障从而触发选举。那么问题来了,比如说现在的7个节点的复制集已经稳定了,当网络出现大延迟的时候,DC1跟DC2之间已经无法正常传送心跳信息了,此时会发生什么情况?
DC1由于有一个主节点了,所以它的一主三从不会发生变化,但是DC2由于探测不到DC1的主节点从而三个从节点触发选举,会在三个节点中选出一个主节点来,此时一个复制集中出现了两个主节点就会导致数据不一致性。当MongoDB使用了大多数原则时当两个机房之间在遇到网络延迟时就不会发生出现两个主节点的情况了。当DC1探测不到DC2时,DC1由于有一个主节点了,所以它的一主三从不会发生变化。而DC2中的三台从节点由于不满足大多数原则(存活主机小于总主机数的1/2)所以不会产生选举,所以三个节点不会有是变化。
1、选举触发条件
1) 主节点故障
2) 主节点网络不可达(默认心跳信息为10秒)
3) 人工干预(rs.stepDown(600))
2、影响选举的因素
1)复制集心跳检测
Mongodb复制集成员之间的联系跟所有高可用所用的机制相同,那就是“心跳监测”机制,默认从节点会2秒一次地向主节点发出心跳监测请求,如果对方在10秒之内没有回应的话,就会认为节点故障。
当主节点不可达时,复制集会做一个判断,其他成员是否对主节点也不可达。如果都不可达那么复制集就会产生新的选举争取选出一台主节点从新为应用程序提供服务。
其他节点不可达时,
2)成员优先级
一个复制集稳定的初选后,选举算法将作出努力尝试把具有最高优先级的可用从节点呼叫出出来选举。比如,如果在复制集中主节点的优先级大于默认值1,那么当主节点宕机重新恢复后成为从节点但由于优先级大于现有的主节点从而会重新取得主节点状态。当priority为0时表示永远没有资格成为主节点,且priority的值为0也是设置隐藏节点及延迟节点的前提条件。
3)网络隔离
网络隔离影响了选举中多数选票的结构,如果主节点不可用了,且每个相互隔离的网络中都没有多数选票的出现,那么复制集将不会选举出新的主节点。复制集将变为只读的。为了避免这种情况的出现,我们需要将多数节点置于主数据中心,少数节点放于其他数据中心。
4)Replication Election Protocol
3.2新版功能,MongoDB版本1的复制协议减少复制集切换时间和加速同时初选的检测。新的复制集默认情况下使用版本1,旧的MongoDB使用版本0是以前版本的协议。
3、复制集高可用选举过程
https://www.cnblogs.com/ExMan/p/9665110.html
三:复制集成员的配置和管理
1.使用rs辅助函数修改副本集配置
添加新成员
>rs.add("192.168.1.25:27017") //ip:端口号
>rs.add({"_id":5,"host":"hadoop04:20017","priority":0,"hidden":true}) //以文档的形式配置更多新成员信息
删除成员
>rs.remove("192.168.1.25:27017") //ip:端口号,删除成员的时候会得到很多无法连接数据库的错误信息,这是正常的。重新配置之后,副本集中会暂时没有主节点,之后会恢复正常。
查看副本集的配置信息
>rs.config() //每次修改副本集的时候,"version"都会自增,它的初始值为1
修改副本集成员信息
>var config=rs.config()
>config.members[1].host="server-1:27017"
>rs.reconfig(confid)
设置成员的投票权
>rs.add({"_id":5,"host":"hadoop04:20017","votes":0})
也可以为已有成员设置投票权,修改之后成员不能投主动票但是可以投否定票
强制重新配置
>rs.reconfig(config,{"force":true})
//在不发生更新的节点执行
注意:
- 不能修改成员的"_id"字段
- 不能将接受rs.reconfig命令的成员的优先级设置为0
- 仲裁者非仲裁者不能切换
- 不能将"buildIndexes"=false的成员修改为"buildIndexes"=true
2.添加仲裁者
对于某一些只需要两份数据的场景,只有两个节点存数据但是不能影响选举,就可以添加一个仲裁者(arbiter)
将要添加的仲裁者节点的配置文件,使用repSet副本集名称和空的数据目录。
rs.addArb("server4:27017")
也可以在成员配置中指定arbiterOnly选项,这与上面的效果一样
rs.add({"_id":4,"host":"server-5:27017","arbiterOnly":true})
注意:最多只能使用一个仲裁者,尽量在副本集中使用技术哥数据成员而不要使用仲裁者
3.设置优先级
优先级的范围在0~100,优先级为0的成员永远不能成为主节点。拥有最高有限级的节点会优先选举为主节点。
>var config=rs.config()
>config.members[1].priority=1.5
4.隐藏成员
隐藏成员对客户端不可见,在其他复制源完好的情况下,隐藏成员不会成为复制源。只有优先级为0的成员才可以被设置为隐藏成员。
var config=rs.config()
config.members[2].hidden=0
config.members[2].priority=0
5.创建索引
可以指定 "buildIndexs":false,这个选项可以阻止备份节点创建索引,但是如果指定了"buildIndexes":false的成员永远无法恢复为可以创建索引的正常成员,这个选项也要要求优先级为0
6.修改成员状态
复制集中成员的状态:
-
STARTUP:成员刚启动的时候处于这个状态,MongoDB尝试加载成员的副本集配置
-
STARTUP2:整个初始化同步过程都处于这个状态,普通结点只会维持这个状态几秒,这个状态下MongoDB会创建一个线程,用于处理复制和选举,之后会切换到RECOVERING
-
RECOVERING:此状态成员不能处理读请求,处于维护模式,成员脱节或者处理非常耗时的操作的时候会进入,在启动过程中成为备份节点之前也会经历这个状态
-
ARBITER:仲裁者处于的状态
-
DOWN:正常运行的成员处于不可达状态,可能是网络原因
-
UNKNOWN:表明未知状态的成员挂掉了,可能是网络问题
-
REMOVED:当成员被移除副本集就处于这个状态
-
ROLLBACK:正在进行数据回滚的成员处于这个状态
6.1 将主节点变为备份节点
>rs.stepDown() //让主节点退位为副节点并且维持60s
>rs.stepDown(300) //5分钟
6.2 阻止选举
在主节点退位的情况下,希望一定时间内备份节点一直处于备份状态
//每个节点都执行
>rs.freeze(1000)
//释放备份节点的阻止选举状态
>rs.freeze(0)
6.3 使用维护模式
可以在副本集成员在做很耗时的操作的时候强制副本集成员进入RECOVERING状态,不处理读请求也不作为复制源。使用replSetMaintenanceMode.如果一个成员远远落后主节点,不希望处理读请求的时候,可以强制其进入维护模式。
>function maybeMaintenanceMode(){
var local=db.getSisterDB("local");
//如果成员不是备份节点,就直接返回
if(!local.isMaster().secondary){
return;
}
//查找这个成员最后一次操作的时间
var last=local.oplog.rs.find().sort({"$natural":-1}).next();
var lasttime=last['ts']['t'];
//如果落后主节点30s以上
if(lasttime<(new Date()).getTime()-30){
db.adminCommand({"replSetMaintenanceMode":true});
}
};
将成员从维护模式中恢复
db.adminCommand({"replSetMaintenanceMode":false});