Nacos微服务注册中心-Raft选举算法简析( 二 )


第一种情况,赢得选举之后,leader会给所有节点发送消息,避免其他节点触发新的选举
第二种情况,比如有三个节点A B C 。A B同时发起选举,而A的选举消息先到达C,C给A投了一票,当B的消息到达C时,已经不能满足上面提到的第一个约束,即C不会给B投票,而A和B显然都不会给对方投票 。A胜出之后,会给B,C发心跳消息,节点B发现节点A的term不低于自己的term,知道有已经有Leader了,于是转换成follower
第三种情况,没有任何节点获得majority投票,可能是平票的情况 。加入总共有四个节点(A/B/C/D),Node C、Node D同时成为了candidate,但Node A投了Node D一票,NodeB投了Node C一票,这就出现了平票 split vote的情况 。这个时候大家都在等啊等,直到超时后重新发起选举 。如果出现平票的情况,那么就延长了系统不可用的时间,因此raft引入了randomized election timeouts来尽量避免平票情况
 
数据的处理:
对于事务操作,请求会转发给leader;
非事务操作上,可以任意一个节点来处理;
 
 
三、日志复制(Log Replication)日志复制的流程大体如下:

  • 每个客户端的请求都会被重定向发送给leader,这些请求最后都会被输入到raft算法状态机中去执行 。
  • leader在收到这些请求之后,会首先在自己的日志中添加一条新的日志条目 。
  • 在本地添加完日志之后,leader将向集群中其他节点发送AppendEntries RPC请求同步这个日志条目,当这个日志条目被成功复制之后,leader节点将会将这条日志输入到raft状态机中,然后应答客户端 。
Raft日志的组织形式如下图所示:
Nacos微服务注册中心-Raft选举算法简析

文章插图
 
每个日志条目包含以下成员:
1. index:日志索引号,即图中最上方的数字,是严格递增的 。
2. term:日志任期号,就是在每个日志条目中上方的数字,表示这条日志在哪个任期生成的 。
3. command:日志条目中对数据进行修改的操作 。
 
一条日志如果被leader同步到集群中超过半数的节点,那么被称为“成功复制”,这个日志条目就是“已被提交(committed)” 。如果一条日志已被提交,那么在这条日志之前的所有日志条目也是被提交的,包括之前其他任期内的leader提交的日志 。如上图中索引为7的日志条目之前的所有日志都是已被提交的日志 。
 
 
四、为什么 Raft 通常推荐使用奇数节点而不是偶数节点?Raft 一般会使用奇数个节点,比如 3,5,7 等等 。这是因为 raft 是 一种基于多节点投票选举机制的共识算法,通俗地说,只有超过半数节点在线才能提供服务 。这里超过半数的意思是N/2+1(而不是N/2),举例来说,3 节点集群需要 2 个以上节点在线,5 节点集群需要 3 个以上节点在线,等等 。对于偶数节点的集群,2 节点集群需要 2 节点同时在线,4 节点集群需要 3 节点在线,以此类推 。实际上不只是 Raft,所有基于 Quorum 的共识算法大体上都是这么个情况,例如 Paxos,Zookeeper 什么的,本文仅以 Raft 为例讨论 。
 
共识算法要解决的核心问题是什么呢?
是分布式系统中单个节点的不可靠造成的不可用或者数据丢失 。Raft 保存数据冗余副本来解决这两个问题,当少数节点发生故障时,剩余的节点会自动重新进行 leader 选举(如果需要)并继续提供服务,而且 log replication 流程也保证了剩下的节点(构成 Quorum,法定人数)总是包含了故障前成功写入的最新数据,因此也不会发生数据丢失 。
我们对比一下 3 节点的集群和 4 节点的集群,Quorum 分别是 2 和 3,它们能容忍的故障节点数都是 1 。如果深究的话,从概率上来说 4 节点集群发生 2 节点同时故障的可能性要更高一些 。于是我们发现,相对于 3 节点集群,4 节点集群消耗更多的硬件资源,却换来了更差的可用性,显然不是个好选择 。
 
 
五、Nacos Naming服务一致性实现Naming服务支持两种类型的数据存储:临时和永久数据 。永久数据一旦创建之后会一直存在,除非显式删除;临时数据创建之后和所有者的生命周期绑定,需要创建者不断发送心跳信息来保证数据的有效性 。
Nacos微服务注册中心-Raft选举算法简析

文章插图
 
1. RaftConsistencyServiceImpl类
RaftConsistencyServiceImpl类提供的是基于Raft协议的永久数据存储方案 。nacos naming服务内部实现了一个简化的Raft协议 。每个节点通过本地文件系统保存所有数据,通过Raft协议选择Leader并同步数据 。Raft协议通过保证数据在各naming节点的一致性来保证naming服务的高可用 。


推荐阅读