Raft实现报告(三)复制日志
紧接上文,Raft系统为了保持每次成功选出Leader的概率更大,引入了随机选举超时机制,且在新选举开始时每个follower的改时间都会重新随机。Leader选举完成之后,形成一位Leader多位follower的局面之后的事请。
Log replication
一旦Leader成功选举出来,他就开始服务客户端的请求,注意这里Leader开始对外提供服务,此处不是集群的RPC服务。客户端的请求都会包含命令,将会被复制(replicated我真不懂怎么翻)状态机执行。Leader会将这次操作记成log作为新的条目,然后并行发送AppendEntries RPC给集群中的所有server复制该log。
当这些条目被成功复制之后,leader提交这些条目到他自己的状态机中返回执行结果给客户端。(client请求->Leader记录->Leader分发复制给follower->确认成功后->执行->返回结果给client),可以看到步骤非常多,在这之间如果follower宕机了或响应的非常慢,或发生了网络丢包的问题,leader会一直重试AppendEntries RPC(甚至在Leader已经将结果返回给client之后,那也就是说Leader不需要等到确认所有follower都复制好log之后就能响应客户端了???)直到所有follower最终储存了所有log条目。这是为了保持一致性。或者说为了保持一致性,就必须这样做。
每一个日志条目存储了leader收到这条消息的term编号已经存进状态机的命令内容。其中的term编号被用于检测log条目是否一致,已经维持一些前文中提到的安全特性。每个日志条目还包含一个整数索引确定自己在整个log中的位置。
Leader会决定安全提交日志条目到状态机的时间,这种提交的状态就叫committed,Raft会保证所有committed的条目最终会被所有正常工作的状态机执行。一旦一个日志条目被提交了committed,Leader就会将他复制到大多数的server当中去,出该条之外!所有Leader先前committed的log条目也会被复制过去,甚至包括前一任Leader的所有条目,那就是持续追加呗。
Leader会持续跟踪他所知道最大索引的committed点。他包括AppendEntriesRPC的将来索引,确保其他server最终能查找到(这部分没太看懂)。一旦follower知道了一条log条目是committed的,他就会提交该条目到本地状态机,保持原来顺序。
为什么斯坦福学生设计这种log机制
为了再不同的服务器之前,维持log的高度一致性,也能说明一个以前看到的问题,就是分布式系统的一致性问题是什么带来的,不是数据的并发读写,而是来自内容的复制。他们设计的这种方案不仅简化系统行为,也让行为变地更加好分析和预测。也就是说我们对结果一定是保持肯定的。最重要的一点就是保持安全性。
- 如果两个日志条目再不通的logs中间有相同的index和term,那他们储存的相同的命令。
- 如果两个日志条目再不通的logs中间有相同的index和term,那过去的所有日志条目都是相同的
第一条遵循了leader在创建条目的时候,在term和index的限制下, 最多只能创建一条日志条目,并且日志条目从来不改变自身的位置(log entry(term=1, index=1)),第二条可以被AppendEntries RPC执行的一致性检查所保证。当发送一条AppendEntries RPC的时候,Leader的logs的term和index会立刻超过新的条目(麻了)。如果follower没有在他的logs中发现带有相同index和term的日志条目。那他就会拒绝该条目。
一致性检查表现为一个归纳步骤:
日志的初始状态为空满足Log Matching
一致性检查在日志拓展时保留Log Matching属性
当每个AppendEntries成功返回时,Leader将会通过新条目知道follower的日志跟自己的日志相同