日志复制能够说是Raft集群的核心之一,保证了Raft数据的一致性,下面经过几张图片介绍Raft集群中日志复制的逻辑与流程;并发
在一个Raft集群中只有Leader节点可以接受客户端的请求,由Leader向其余Follower转发全部请求日志,而且有那么两条规则:Leader不删除任何日志、Follower只接收Leader所发送的日志信息;3d
此图介绍了Raft集群中日志的组成结构,日志由序号与条目组成,每一个条目又由任期与指令组成,committed范围内为已提交的日志是指过半节点已经接收并存储的日志;日志
上图从整个上介绍了Raft集群的日志复制流程,Leader接收到指令后写入到本地日志,在随后的心跳中(AppendEntries)往其余追随者发送该条目,等待收到过半追随者响应后将该条目标志位已提交状态,并发往状态机执行,完成后返回结果给客户端;在后续心跳包(AppendEntries)中通知全部追随者哪些条目为已提交状态,以便追随者更新在本身状态机中执行该指令; 只有Leader可以接受客户端的指令,追随者只可以接收领导者的AppendEntries请求;blog
在Raft集群中可经过条目索引号、任期号惟一肯定一个条目,该条目前序全部条目也是一致的,如上图中索引号为5的条目为已提交状态的条目,则从索引号1到5的全部条目均为已提交的状态;索引
上图中Leader发送AppendEntries请求时带有其前序索引位置四、前序任期号2,发往Follower一、Follower2;
Follower1因为前序索引与前序任期能匹配本地条目因此将会接受该请求;
Follower2因为前序索引与前序任期未可以匹配因此拒绝该请求;图片
Raft处理日志不一致的状况是经过强制追随者复制领导者日志来调整日志一致性的,因此当追随者与领导者出现日志不一致时,追随者日志将会被领导者日志覆盖;get
要使领导者与追随者保持一致性的状态,须要二者找到一致性的位置,删除追随者该位置以后全部日志条目,发送领导者日志给追随者;
领导者经过在每个追随者维护了一个 nextIndex,表示下一个须要发送给跟随者的日志条目索引地址,领导者刚得到选举时,初始化全部 nextIndex 值为本身的最后一条日志的index加1;当追随者的日志和领导者不一致,那在下一次的AppendEntries时的一致性检查会失败,被追随者拒绝后,领导者就会减少 nextIndex 值进行重试,nextIndex 会在某位置使领导者和追随者日志达成一致。
当日志达成一致时,追随者会接受该AppendEntries请求,这时追随者冲突的日志条目将所有被领导者的日志所覆盖。一旦AppendEntries成功,那么跟随者的日志就会和领导人保持一致,而且在接下来的任期里一直继续保持。it
参考资料:
http://ramcloud.stanford.edu/raft.pdfclass
文章首发地址:Solinx
http://www.solinx.co/archives/1221pdf