Raft算法属于Multi-Paxos算法,它是在Multi-Paxos思想的基础上,做了一些简化和限制,比如增加了日志必须是连续的,只支持领导者、跟随者和候选人三种状态,在理解和算法实现上都相对容易许多
从本质上说,Raft算法是通过一切以领导者为准的方式,实现一系列值的共识和各节点日志的一致
Raft算法支持领导者(Leader)、跟随者(Follower)和候选人(Candidate)3种状态:
Raft算法是强领导者模型,集群中只能有一个领导者
在初始状态下,集群中所有的节点都是跟随者状态
Raft算法实现了随机超时时间的特性,每个节点等待领导者心跳信息的超时时间间隔是随机的。上图中,集群中没有领导者,而节点A的等待超时时间最小,它会最先因为没有等到领导者的心跳信息,发生超时
这时,节点A增加自己的任期编号,并推举自己为候选人,先给自己投上一张选票,然后向其他节点发送请求投票RPC消息,请它们选举自己为领导者
如果其他节点接收到候选人A的请求投票RPC消息,在编号为1的这届任期内,也还没有进行过投票,那么它将把选票投给节点A,并增加自己的任期编号
如果候选人在选举超时时间内赢得了大多数的选票,那么它就会成为本届任期内新的领导者
节点A当选领导者后,它将周期性地发送心跳消息,通知其他服务器我是领导者,阻止跟随者发起新的选举
在Raft算法中,服务器节点间的沟通联络采用的是远程过程调用(RPC),在领导者选举中,需要用到这两类的RPC:
Raft算法中每个任期由单调递增的数字(任期编号)标识,任期编号是随着选举的举行而变化的
领导者周期性地向所有跟随者发送心跳消息(即不包含日志项的日志复制RPC消息),通知大家我是领导者,组织跟随者发起新的选举
如果在指定时间内,跟随者没有接收到来自领导者的消息,那么它就认为当前没有领导者,推举自己为候选人,发起领导者选举
在一次选举中,赢得大多数选票的候选人,将晋升为领导者
在一个任期内,领导者一直都会是领导者,直到它自身出现问题(比如宕机),或者因为网络延迟,其他节点发起一轮新的选举
在一次选举中,每一个服务器节点最多会对一个任期编号投出一张选票,并且按照先来先服务的原则进行投票。比如节点C的任期编号为3,先收到了一个包含任期编号为4的投票请求(来自节点A),然后又收到了一个包含任期编号为4的投票请求(来自节点B)。那么节点C将会把唯一一张选票投给节点A,当再收到节点B的投票请求RPC消息时,对于编号为4的任期,已没有选票可投了
选举是跟随者发起的,推举自己为候选人;大多数选票是指集群成员半数以上的选票;大多数选票规则的目标,是为了保证在一个给定的任期内最多只有一个领导者
Raft算法使用随机选举超时时间的方法,把超时时间都分散开来,在大多数情况下只有一个服务器节点先发起选举,而不是同时发起选举,这样就能减少因选票瓜分导致选举失败的情况
在Raft算法中,随机超时时间有2种含义:
1)Raft算法的强领导者模型选举限制和局限如下:
2)强领导者模型会限制集群的写性能,有什么办法能突破Raft集群的写性能瓶颈呢?
参考Kafka的分区和ES的主分片副本分片这种机制,虽然写入只能通过Leader写,但每个Leader可以负责不同的片区,来提高写入的性能
副本数据是以日志的形式存在的,日志是由日志项组成,日志项是一种数据格式,它主要包含用户指定的数据,也就是指令(Command),还包含一些附加信息,比如索引值(Log index)、任期编号(Term)
首先,领导者通过日志复制(AppendEntries)RPC消息,将日志项复制到集群其他节点上
接着,如果领导者接收到大多数的复制成功响应后,它将日志项应用到它的状态机,并返回成功给客户端。如果领导者没有接收到大多数的复制成功响应,那么就返回错误给客户端
领导者将日志项应用到它的状态机,怎么没通知跟随者应用日志项呢?
因为领导者的日志复制RPC消息或心跳消息,包含了当前最大的、将会被提交的日志项索引值。所以通过日志复制RPC消息或心跳消息,跟随者就可以知道领导者的日志提交位置信息
在Raft算法中,领导者通过强制跟随者直接复制自己的日志项,处理不一致日志。也就是说,Raft是通过以领导者的日志为准,来实现各节点日志的一致性的
引入2个新变量:
领导者通过日志复制RPC一致性检查,找到跟随者节点上与自己相同日志项的最大索引值,然后复制并更新覆盖该索引值之后的日志项,实现了各节点日志的一致。跟随者中的不一致日志项会被领导者的日志覆盖,而且领导者从来不会覆盖或者删除自己的日志
1)领导者接收到大多数的“复制成功”响应后,就会将日志应用到它自己的状态机,然后返回“成功”响应客户端。如果此时有个节点不在“大多数”中,也就是说它接收日志项失败,那么在这种情况下,Raft会如何处理实现日志的一致呢?
处理日志项一致通过RPC一致性检查,找到跟随者中与自己相同日志项的最大索引,然后把后面的日志项同步过去,让跟随者复制更新
2)Raft在处理日志不一致时会给跟随者发送RPC一致性检查,找到和自己相同日志项的最大值,这里是对每个跟随者而言的还是所有的跟随者而言的?
日志复制信息对每个跟随者都要单独维护的
参考:
07 | Raft算法(一):如何选举领导者?
08 | Raft算法(二):如何复制日志?