MongoDB的复制集具备自动容忍部分节点宕机的功能,在复制集出现问题时时,会触发选举相关的过程,完成主从节点自动切换。每一个复制集成员都会在后台运行与复制集全部节点的心跳线程,在两种状况下会触发状态检测过程:ide
(1)检测自身是否处于选举过程,若是是,退出本次过程。
(2)维护一个主节点的备用列表,列表中全部节点均可能被选举为主节点,每一个节点都会检测自身以及全局条件是否知足:
a. 是否看见复制集中有Majority在线。
b. 自身priority大于0。
c. 自身不为arbiter。
d. 自身opTime不能落后于最新节点10s以上。
e. 自身存储的集群程序按信息为最新。
若是全部条件知足,则将自身添加到主节点备用列表中,不然,将自身从列表中移除。线程
检测如下条件,若都知足,将主节点降为从节点(若是要降级的主节点是自身,直接调用降级方法,若是不为自身,调用replSetStepDown命令将复制集主节点降级为从节点: a. 集群中主节点存在。 b. "主节点的备用列表”中存在比当前的主节点priority更高的节点。 c. "主节点的备用列表”中priority最高的节点,其opTime要比其余全部节点最新的opTime落后10s之内。 d. 检测自身是否为主,若为主,且自身没法看见复制集的Majority在线,将自身降级为从。 e. 若是看不见集群中有主节点存在,检测自身是否在”主节点的备用列表”,若不在,打印log并退出此流程。 f. 若自身在”主节点的备用列表”中,开始判断自身能否向复制集中发送选举自身为主节点的通知,判断过程包含: 1> 自身是否能够看见复制集中的Majority在线。 2>自身是否在”主节点的备用列表”。
若条件知足,则设置”自身已经在选举过程当中”标识位为true,并进入”选举自身为主节点”方法。
方法中会验证自身是否知足如下条件:
a. 此线程拿到了线程锁。
b. 此节点没有被配置slaveDelay选项或者配置的slaveDelay为0。
c. 此节点没有被配置为arbiter。
若知足,则调用环境检测,若如下条件被触发,则不发送"选举我为主节点”投票:
1> 当前时间小于steppedDown的结束冻结时间(为执行steppedDown时的时间+冻结设定时间,内部调用为60s)。
2> 本身的opTime不是全部节点最新的。
3> 如有节点opTime比本身新,直接退出此流程。
若是其余最新的节点最多与本身同样新,每有一个这样的节点,随机sleep一段时间,以后继续判断。
a. 本身上线5分钟内且复制集中不是全部节点在线。
b. 如无其余问题,尝试获取本身进行投票时的票数,在此过程当中,会判断本身在30s内是否进行过投票,如进行过,直接退出整个过程。
通过以上种种复杂的检测,终于能够向复制集发送”选举我为主节点”的投票。
发送以后,会接收来自全部节点的投票,若得票数小于等于一半,不将本身变为主节点,若超过一半,设置本身为主节点。
投票结束后,设置”自身已经在选举过程当中”标识位为false。
能够看到,上面的判断逻辑有一些是重复判断,不过不影响最终结果,可能与判断逻辑较为复杂有关系,在每一个决定以前都要验证全部条件是否知足,防止有条件被漏掉。
在复制集中的节点收到其余节点发送的”选举我为主节点”投票信息时,会有如下的判断:
a. 若自身存储的复制集配置版本太低,不投票。
b. 若发起请求的节点存储的复制集配置版本太低,投反对票。
c. 若是自身所在的复制集没有发起投票的节点,投反对票。
d. 复制集中存在主节点,投反对票。
可参与选举的节点中有priority高于请求为主的节点存在时,投反对票。
若是全部条件经过,获取自身的投票数(一样会判断自身在30s内是否参加过投票,若参加过,再也不投票),投出票数。
须要说一下的是,一个反对会将最终票数减10000,即在绝大多数状况下,只要有节点反对,请求的节点就不能成为主节点。
选举过程很复杂,实际使用中总结为两点:
通常状况下须要5s左右进行选主。
若是新选举出的主节点立马挂掉,至少须要30s时间从新选主。code