本篇文章主要介绍一下MongoDB什么时候开始选举?如何选举的?以及一些参数的介绍。

当复制集初始化(initiating)或者primary失效时,都会触发选举(election),这个过程不需要人工介入。

    选举过程需要消耗一些时间,在此期间,集群将不能接收write操作(即使旧的primary仍然存活,但因为“网络分区”问题导致它不能与其他secondaries通讯),所有的members(包括旧的primary)都处于只读状态,如果集群中没有“多数派”的members处于有效,那么将无法选举出primary,直到足够的member加入,此时整个复制集处于只读,无法接收write请求。

1Heartbeats复制集中的所有members之间都互相建立心跳连接,且每隔两秒发送一次心跳,如果未在10秒内收到回复,则此member将会被标记为“不可用”。

2Priority比较每个member都有权重值,默认为都为1,members倾向于选举权重最高者。上述提到,priority为0的member不能被选举为primary且不能发起选举;只要当前primary的权重最高或者持有最新oplog数据的secondaries没有比它更高的权重时,集群不会触发选举。如果一个拥有更高权重的member加入集群,则会首先catch up当前primary,然后重新发起一轮选举,并将此member选举为primary。

3Optime当前member已经从primary的oplog中应用的最后一个operation的时间戳(此时间戳有primary生成,在oplog中每个操作记录都有);一个member能成为primary的首要条件就是在所有有效的members中它持有最高的optime。

4Connections一个member要成为primary,它必须与“多数派”的其他members建立连接,如果未能与足够多的member建立连接,事实上它本身也无法被选举为primary;不过对于谁将成为priamry而言,多数派参考的是“总票数”,而不是member的个数,因为我们可以给每个member设定不同的“票数”。比如有三个member,每个member持有一票(vote),那么只要至少有2个member可以互相通信(3的多数派至少为2),即可选举;不过如果有2个member不可用,将无法选举,剩余的那个member如果是primary,那么它也将step down并成为secondary,整个复制集处于只读状态。

5)网络分区(Network Partitions即集群中一部分members无法与其他members通讯,而分割成多个区域;因为选举是基于“多数派”(一个member需要与多数派建立连接,且票数也是多数派),所以网络分区时,无法进行选举(未能形成多数派时)。为了避免这种问题,建议将集群中的多个members分别部署在多个物理网段中。

 

选举触发时机

1)复制集初始化时,此时没有primary

2)一个secondary与primary失去连接,此时它将发起选举;如果多数派的secondaries均与primary失去连接,则选举即可进行成功,否则选举将会被正常的members否则(veto)。

3)primary关闭(step down)。

需要注意:

“Priority 0”将无法发起选举,即使它与primary失去连接,它只能对别人的选举进行“投票”或者“否决”。

我们可以通过rs.stepDown()方法或者replSetStepDown命令来关闭primary,或者当有更高优先级的secondary加入时,或者当前primary无法与大多数members建立连接时,primary也会关闭,此后将触发新一轮的选举。

此外,我们通过rs.reconfig()修改了复制集的配置后,也有可能会触发选举。当primary关闭时,它会关闭所有的客户端连接,此后客户端将无法write。

 

选举规则:

    每个member都有一个priority属性,用来表示它们成为primary的资格,集群将会选举priority最高的member成为primary,默认情况下,所有的member的权重均为1,即它们有相同的机会成为primary。如果你倾向于某个member成为primary,可以将其priority的值设置的更高。默认情况下,每个member持有一个vote(票数),如果大多数member都选举某个member,那么它将成为primary;“Non-voting” member的vote值为0,且目前所有的membervote值不能大于1。(即每个member只能投一票,或者不投票)

 

选举中否决:

    所有的member都可以否决选举,包括“Non-voting”。将会在如下情况时否决选举(否决提议者):

1)如果提议选举的member不属于当前复制集(配置文件中未声明)

2)提议选举的member数据陈旧  

3)提议选举的member priority比已知的其他member低

4)如果当前primary比提议选举者持有更高的optime 

如果权重最高的member没有持有最高的optime,那么它将首先跟进optime最高的secondary,然后才能成为primary,言外之意priority权限最高的最终会是primary

 

Rolled back

    前文已经提到“rolled back”:priamry失效之前,未能把write操作复制给大多数secondaires,此后选举出了新的primary,那么新的priamry也接受了部分write请求,那么当旧的priamry再次加入集群,它上面的数据有一些与当前priamry是“不对齐”的,那么旧的priamry则需要将那些“未对齐的”数据进行回滚,并与新的priamry保持数据一致。通常情况下,我们应该避免“rolled back”,因为这是一种比较危险的“数据不一致”的情况。rolled back数据被保存在“dbPath”路径下rollback目录中。

    默认情况下,客户端的write concern为{w : 1}即write操作在primary上写入成功后就会向客户端返回结果,这种情况下,如果primary失效且数据尚未复制到secondaries时,会发生rolled back。为了避免rollback,客户端可以使用{w : majority},当write操作在大多数secondaries上写入成功后才会向客户端返回结果。