Raft日志复制原理
第一阶段:请求到达Leader
Leader收到请求后把它作为日志条目Entry写入本地日志中,状态是未提交。
第二阶段:Leader把日志条目发送到其他Follower
1.为什么Leader向Follower发送的Entry是AppendEntries呢?
因为Leader与Follower的心跳是周期性的,而一个周期间Leader可能接收到多条客户端的请求,因此,随心跳向Followers发送的大概率是多个Entry,即AppendEntries。
2.Leader向Followers发送的不仅仅是追加的Entry(AppendEntries)。
在发送追加日志条目的时候,Leader会把新的日志条目紧接着之前条目的索引位置(prevLogIndex),Leader任期号(Term)也包含在其中。如果Follower在它的日志中找不到包含相同索引位置和任期号的条目,那么它就会拒绝接收新的日志条目,因为出现这种情况说明Follower和Leader不一致。
3.如何解决Leader与Follower不一致的问题?
Leader回溯找到最近两者一致点,删除从那个点之后的所有日志条目,发送自己的日志给Follower。所有的这些操作都在进行附加日志的一致性检查时完成。
Leader为每一个Follower维护一个nextIndex,它表示下一个需要发送给Follower的日志条目的索引地址。当一个Leader刚获得权力的时候,它初始化所有的nextIndex值,为自己的最后一条日志的index加1。如果一个Follower的日志和Leader不一致,那么在下一次附加日志时一致性检查就会失败。在被Follower拒绝之后,Leader就会减小该Follower对应的nextIndex值并进行重试。最终nextIndex会在某个位置使得Leader和Follower的日志达成一致。当这种情况发生,附加日志就会成功,这时就会把Follower冲突的日志条目全部删除并且加上Leader的日志。一旦附加日志成功,那么Follower的日志就会和Leader保持一致,并且在接下来的任期继续保持一致。
第三阶段:Leader等待Followers回应
Followers接收到Leader发来的复制请求后,有两种可能的回应:
1.写入本地日志中,返回Success;
2.一致性检查失败,拒绝写入,返回False。
当Leader收到大多数Followers的回应后,会将第一阶段写入的Entry标记为提交状态。
第四阶段:Leader回应客户端
完成前三个阶段后,Leader会向客户端回应OK,表示写操作成功。
第五阶段:Leader通知Followers Entry已提交
Leader回应客户端后将随着下一个心跳通知Followers,Followers收到通知后将Entry标记为提交状态。Raft集群超过半数节点已经达到一致状态,确保强一致性。
参考资料