zoukankan      html  css  js  c++  java
  • MongoDB Replica Set 选举过程

    Replica Set 选举过程

    心跳检测

    假设我们有三个节点的replica sets:X,Y和Z节点。在replica sets结构中,这三个节点每2秒会各自向其它两个节点发送一个心跳检测请求。比如X节点向Y和Z节点各发送了一个心跳检测请求,在正常情况下,Y、Z会返回一个包含自身信息的回复包,回复包中主要包括了下面一些信息:它们现在是什么角色(primary 还是 secondary),他们是否能够在必要的时候成为 primary,以及他们当前时钟时间等等。

    X节点在收到回复包后,会用这些信息更新自己的一个状态映射表,更新的内容包括:是否有新的节点加入或有老的节点宕掉,这个请求的网络传输时间等等。

    而当X节点的映射表发生了变化,那X会进行下面的逻辑判断:如果X是 primary,而另外一个节点出现故障,那么它会那自己是否还能和集群中大多数节点进行通信,如果不能与大多数节点通信,那么他会把自己从 primary 降级为 secondary。(在replica sets中,primary 必须能够和集群中的大多数节点进行通信,以免发生网络断开形成两个或多个节点群各自为政的情况,这样会影响到数据的一致性)

    关于降级

    在节点从 primary 降级为 secondary 的过程中,会有一些问题出现。在 MongoDB 中,写操作默认是通过 fire-and-forget 的模式来进行的,也就是说写操作通常不关心是否成功,发完请求后客户端就认为成功了。但如果这时候 primary 进行降级操作,那么客户端并不知道这时候 primary 已经降级成为 secondary 了,客户端可能还会将后续的写操作发送给这个节点。这时候刚刚降级的这个 secondary 可以发送一个包说“我已经不是 primary 了”,但是我们上面说过了,客户端根本就无视你这个包。所以客户端根本不知道这次写入已经失败了。

    对于这个问题,你可能会说”那我们每次都使用安全写入不就行了“(安全写入意思是说等待服务器返回成功后客户端才认为写成功了),但是很明显,这非常不靠谱。所以我们的做法是,在一个 primary 降级成为 secondary 后,它会将原来的所有连接关闭。这样客户端在下一次写入的时候就会出现 socket 错误。而客户端在发现这个错误之后,就会重新向集群获取新的 primary 的地址,并将后续的写操作都往新的服务器上写入。

    选举

    我们回头再来看心跳监测请求:如果X是一个 secondary,那么X会定时检测是否需要选举自己成为 primary。其检测内容包括:是否集群中有其它节点认为自己是 primary?X节点自己是否已经是 primary?X节点自己是否有资格成为 primary?如果这三个问题中的任何一个回答是否定的,那么X节点就不会试图把自己变成primary。(也就是说,只有当X节点是一个能够当 primary 的secondary,并且其它节点都不是primary时,X才会发起选举并选自己为primary)

    而当X发现现在需要一个 primary 并且自己又正好可以充当时,它就会发起一轮选举:X节点会向Y、Z节点各发起一个请求包,告知他们”我认为我可以接管 primary 的角色,你们觉得怎么样?“

    当Y和Z收到上面的请求包时,他们会进行下面几项检测:他们是否已经知识集群中有一个 primary了?他们自己的数据是否比X节点更新?是否有其它节点的数据比X节点更新?如果上面条件有任何一个满足,那么他们都会认为X不够资格成为 primary,他们会发送一个返回包告知X说”停止选举!“。而如果三个条件都不成立,也就是说他们认为目前集群中确实没有 primary,并且X的数据又是最新的,那么他们会发送返回包告知X说”没问题“。

    如果X收到”停止选举!“的返回,那么他会马上停止选举并保持自己为 sencondary 状态。

    如果X收到所有其它节点都返回说”没问题“,那么他会进入选举过程的第二阶段。

    在第二阶段中,X会向其它节点发送一个包,说”我宣布我已经是 primary 了“。这时候,Y和Z节点再进行一些最终的确认:上面的判断过的所有条件是否依然表明X可以做 primary,如果确实如此,那么他们会在本轮 primary 选举中向X出赞成票。并且他们投完赞成票后,30秒内不会再做其它投票决定。

    上面是说如果第二次确认还是通过的情况,那么如果最终确认没有通过呢。他们会投一个反对票,反对X成为 primary,如果有反对票产生,那么这一轮选举就失败了。X还是保持 secondary 的身份。

    下面我们假设一种情况,如果Y给X投了赞成票,而Z给X投了反对票。那这时候Y由于投了赞成票,它在30秒内不能再进行投票。所以如果这时候Z发起选举想让自己成为 primary,那么Z这时候必须要获得X的赞成票。因为这时候Y不能投票,为了获取多数票,Z必须获得X的赞成票。

    所以投票的规则是这样的:如果没有人投反对票,并且赞成票的比例过半,那么本轮选举对象就能够成为 primary。

  • 相关阅读:
    MySQL5.7 容器化安装
    什么是架构?——软件系统架构的定义
    服务端高并发分布式架构演进之路(转)
    CentOS7 增加回环地址
    三句话看明白jdk收费吗
    【转载】C#里怎么把string类型转换成double
    【转载】如何查看自己网站的搜索引擎收录量和索引量
    【转载】c# datatable 判断值是否存在
    【转载】C#中Datatable修改列名
    【转载】C#使用typeof运算符获取对象变量的具体类型Type
  • 原文地址:https://www.cnblogs.com/sidesky/p/3235051.html
Copyright © 2011-2022 走看看