代码改变世界

Mongodb选举机制

2017-06-29 11:57  Kevin.hhl  阅读(1760)  评论(0编辑  收藏  举报

1.选举协议

下面是官网对老版本和新版本复制协议的简洁说明:

pv0 allows members to veto elections based on member’s optime and priority values.
pv1 does not use vetoes. Individual members can vote for or against a candidate in a particular election, but cannot individually veto (abort) an election unilaterally.

 

pv0: 基于priority 和 optime 选举新主,依赖clock synchronization。

有选举权的节点,每一轮选举最多投一票,在30s内,不能重复投票。

 

pv1:基于Raft协议,每个成员都有 对候选主列表成员投赞成或者反对票,不是单方面否决选举,没有节点投反对票,且获得赞成票数超过有权投票节点总数的1/2,则能成为Primary。否则进入下一轮选举。

因使用了Raft协议,加快  back-to-back选主,减少整个选举新主所需花费的总时间,相应的会增加WriteConcern(w:1)rollback的可能性。

Raft将时间分为多个term,term以连续的整数来标识,每个term以一次election开始,如果有server被选为leader,则该term的剩余时间该server都是leader。

有些term里,可能并没有选出leader,这时候会开启一个新term来继续选主,如上图中的t3。

2.怎么选举?

选举:

假设X是一个Secondary,那么X会定时检测是否需要选举自己成为Primary。其检测内容包括:
1) 是否集群中有其它节点认为自己是Primary?
2) X节点自己是否已经是Primary?
3) X节点自己是否有资格成为Primary?
如果这三个问题中的任何一个回答是否定的,那么X节点就不会试图把自己变成Primary。(也就是说,只有当X节点是一个能够当Primary 的secondary,并且其它节点都不是Primary时,X才会发起选举并选自己为Primary)。

 

投票规则:如果没有节点投反对票,且获得赞成票数超过有权投票节点总数的1/2,则能成为Primary。否则进入下一轮选举。

 

3.2之前(只支持pv0 协议):

replica set最多可以50个节点,但最多有7个节点参与选举,每个节点最多投一票,得到票数最多的为主。
Because a replica set can have up to 50 members, but only 7 voting members, non-voting members allow a replica set to have more than seven members.

影响选举的因素

1)优先级(先看优先级,级别越高,优先为主,priority=0:表示不参与选举、不能成为主

2)optime (如果优先级都相同,则有最新的 optime 的成为主) 注意:集群中 prority 最大,但是optime 不是最新的,落后集群其他最新optime超过10s的prority 最大也不能选为主。

3)心跳 (副本级中的每个member默认都是每2秒ping 其他节点,如果超过{"heartbeatTimeoutSecs" : 10} 默认是10秒没有回应,则标记节点不可达s_down)

 

网络分裂(Network Partition):

如果Primary在少数的那一组,那么次Primary会变成Secondary,多数节点(互相能通信)的那组选举新的主(Primary)。

例外情况:如发生网络分裂,被分裂的一组选举出一个新的Primary,老的Primary还没降级,这就出现了2个Primary,这就是脑裂现象。此时2个Primary都有写入,直到网络恢复后,若老主再次成为Primary,则脑裂过程中选举出的新Primary会回滚脑裂过程新写入的数据;若老主成为Secondary,则回滚老主脑裂过程新写入的数据。

 

>= 3.2开始:

支持pv0 协议、pv1协议,默认是pv1协议。

影响选举的因素

1)Replication Election Protocol(从3.2开始支持protocolVersion: 1)

2)优先级(先看优先级,级别越高,优先为主,priority=0:表示不参与选举、不能成为主

3)optime (如果优先级都相同,则有最新的 optime 的成为主)

4)心跳 (副本级中的每个member默认都是每2秒ping 其他节点,protocolVersion:0如果超过{"heartbeatTimeoutSecs" : 10} 默认是10秒 或者 protocolVersion:1时 electionTimeoutMillis 默认是10秒没有回应,则标记节点不可达s_down,类似Redis sentinel主观下线)

下面status的节点有资格成为选举者:
PRIMARY
SECONDARY
RECOVERING
ARBITER
ROLLBACK

什么时候发生选举主?

1)初始化副本集

2)修改了节点的priority  (config.members[0].priority = 3)

3)网络分裂(当前的Primary和多数的节点不通,当前Primary变成Secondary多数节点的组重新选Primary)

4)当前主上执行rs.stepDown()

5)Secondary ping超过heartbeatTimeoutSecs 后不可达,则标记Primary s_down,发生选主

 

Rollbacks During Replica Set Failover:

以前的primary发生Failover后重新加入副本集,可能需要Rollback。
[root@mongodb-1 data]#ls /data/mongodb/data/rollback/
hydra.feature.2016-09-14T11-18-36.0.bson                         hydra.user_contact.2016-09-14T09-53-55.1.bson
hydra.fraud_metrix_hit_detail_result.2016-09-14T11-18-36.1.bson  hydra.user_contact.2016-09-14T11-18-36.3.bson

 

回滚的限制:

A mongod instance will not rollback more than 300 megabytes of data. If your system must rollback more than 300 megabytes, you must manually intervene to recover the data. If this is the case, the following line will appear in your mongod log:
[replica set sync] replSet syncThread: 13410 replSet too much data to roll back

超过300MB的rollbacks,则需要重新全同步。

影响回滚的配置参数:

settings.catchUpTimeoutMillis:新选举出来的的新主,sync from 集群中有更新的数据同步的时间,在整个过程新主是不可write。其他节点(其他Secondary包括以后加入到集群的老主)都需要从新主同步,他们需要rollback 一些数据,都需要与新主数据对齐(保证数据一致性),增加此参数值,可以减少回滚的数据量,加速回滚;同时也会增加failover 的时间。

 

多次选举:

        并不是每次都是一次就可以选出新主,那么pv0和pv1分别是怎么多次选举?

        假设:有3个节点A、B、C,当集群都是Secondary,此时发生选主时候,有资格成为主的A发起选主(发给集群其他节点,我要成为主),B、C收到A的选主请求后,结果B给A投了赞成票,C给A投了反对票,此时无主,要进入下一轮选主。若下一轮C发起我要成为主,由于B上次投出了赞成票,若是pv0,则30秒内不能再投票,此时C必须获得A的赞成票后才能成为主。若是pv1,B很快就开启下一个term,进入投票,这样对比,pv1 比 pv0  可能更快选出新主。也即Back-to-Back Elections(紧邻选举/多次连续选举)。

       

参考文献:

[1]https://docs.mongodb.com/manual/reference/replica-configuration/

[2]https://docs.mongodb.com/manual/reference/replica-set-protocol-versions/

[3]https://docs.mongodb.com/v3.2/core/replica-set-rollbacks/

[4]http://www.tuicool.com/articles/aeiu2mm