maybeCommit

func (r *raft) maybeCommit() bool {
   mis := make(uint64Slice, 0, len(r.prs))
  for id := range r.prs {
      mis = append(mis, r.prs[id].Match)
  }
  //mis中保存着复制到每个server节点的日志索引,这里进行从大到小排序
  sort.Sort(sort.Reverse(mis))
  //如果节点数量为5,r.quorum()-1=2,则在5个节点中日志第三新的节点的最新日志索引就是复制到过半数节点的日志索引,这个位置的日志可以提交啦
  mci := mis[r.quorum()-1]
  //尝试提交日志
  return r.raftLog.maybeCommit(mci, r.Term)
}

新提交规则


在这种情况下,新的选举规则并不足以保证安全性(Safety),我们还需要修改提交的规则。到目前为止只要领导者发现记录已存于大多数服务器,那么它就认为该记录已被提交。但是为了保证安全性,我们需要增加另一条规则。除了上述规则,领导者必须能看见至少有一条来自于它本任期内的记录也存于大多数服务器。回到之前的例子,如果领导者完成了记录 3-2 的复制,它此时还无法提交该记录并将其发送给状态机,取而代之的是,它必须等待直到它当前任期内的第一条记录(4-4)提交并存于大多数的服务器。至此,两条记录才能都发送给状态机。这么做的原因在于,在这种状态下,服务器 S5 是不可能被选举为下届领导者的,因为有更多的服务器处于更近的任期(任期 4),服务器 S5 只能从服务器 S4 处得到选票。此时,记录 3 和 4 都是安全的。所以将新选举规则来比较日志与新提交规则相结合,我们就能保证 Raft 的安全属性总是有效的。即一旦领导者决定记录已提交,它就会对未来的所有领导者可见。这里我们展示的例子只说明,已提交的记录对下一任期的领导者可见,但也可以很容易就证明,每个未来的领导者也会有相同的日志记录。

日志的不一致

现在我们可以保证安全性,也明白了日志是正确的。那么我们如何让所有跟随者的日志都与领导者保持一致呢?首先,让我们来看看日志不一致可以出现怎样的情况。

  • 跟随者可能会丢失记录(如 (a)-10、(b)-5、(e)-8)
  • 跟随者可能会有不同的记录(如 (d)-11、(f)-4、(c)-6)

需要做的是剔除所有不同的日志记录,并将所有丢失的记录根据领导者的日志填充完整。

修复跟随者的日志

要想恢复到一致状态,领导者会为每个跟随者维护一个状态变量,这个变量称为 nextIndex ,这个变量存储日志的下一条记录的下标位置索引,服务器会把这个位置发送给跟随者(如上图所示,nextIndex = 11)。当一台服务器成为领导者后,它会将 nextIndex 值设置成当前日志记录的下一位置。所以在上面的例子中,任期 7 的领导者的最后一条记录的索引位置是 10 ,那么它会将 nextIndex 设置成 11 。领导者会根据 AppendEntries 调用发现一致性问题,因为当跟随者接收到 AppendEntries 调用时,都会进行检查。这个检查就可以发现所有的问题。所以当下一次领导者想要与跟随者进行通信时,它都会包括下标位置索引(10)以及任期号(6)作为请求的参数。当选为领导者后,下一次请求也有可能是以心跳检测的方式发送的,心跳检测与 AppendEntries 调用的方式一样,只是没有新值创建,但还是包括一致性检查的。所以当消息到达跟随者(a)后,它会将接收到的下标位置索引与任期与自己的日志信息进行比较,并没有匹配的记录,所以它会拒绝 AppendEntries 请求,当领导者收到拒绝的响应之后,它的响应很简单,它要做的只是将 nextIndex 减 1 ,所以这个值就变成了 10 。如此逐一减少,直到最终 nextIndex 为 5 的时候,领导者再次发送请求的信息会包括下标位置索引(4)以及任期号(4),这时它与跟随者(a)当前的日志记录信息是相匹配的,所以这时跟随者会接受 AppendEntries 请求,并追加记录 5-4 。直到领导者将跟随者的日志记录填充完整。相似的过程也会在跟随者(b)上出现。当 nextIndex 减少到 4 时,领导者会包括下标位置索引(3)以及任期号(1)作为请求的参数,并修正跟随者(b)上的日志记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值