raft比较容易混淆的问题

  • 对于写请求,raft的leader和follower之间,是只需要一次网络请求。只要大部分follower回复append entry success,那么leader就修改本地的commit log index,并回复client成功。从这个角度上看,raft是一段提交。
  • 对于读请求,如果允许follower提供读服务,那么要leader下一次的append entry 请求中把当前的commit index发给follower,follower才认为是提交成功,从这个角度上看,读是两段提交。
  • 实际上有了multiraft之后,读只在leader上即可,不需要follower分担读压力。leader收到读请求原则上还需要发起一个raft heartbeat,收到一个多数派响应后确定自己的leader任期之后,才可以回复读请求。实际的工程实现中,为了省去这次raft的网络消息交互,通过leader租约机制,一个lease内leader不重新选举,那lease内leader只需要读本地数据即可。目前tidb/cockroachdb就是这么实现的。
  • 不确定性
  • 某个term内,leader的log entry只在少数派复制成功了,多数派未成功,然后产生了新的leader选举,此后会有两种情况:
    • 如果新的leader是原来少数派的的leader,那么最后一次没有在多数派提交成功的log entry,还将作为leader的log复制下去(如果未足够长的时间内leader未切换);
    • 如果产生的新leader是上一轮没复制成功的多数派,那么少数派上多余的log会被新leader认为不合法而被清除掉。
    • 结论
      • 只要多数派提交成功的,肯定是会做leader的合法日志复制下去;
      • 如果如果少数成功,此时leader不会回复client本次写是成功还是失败,而是继续向组内节点传播本次写请求;如果发生了leader选举,那么这条记录,可能最终会成功,也可能失败。
      • 对于上一个周期内,少数派成功的复制日志,可能作为脏数据被清理,也可能作为合法日志复制下去,这就是raft的不确定性。
    • 事实上,这个不确定性很难消除,比如下一个leader选举周期内,很难保证上一次的少数派不被选举为leader或者一定被选为leader;例如修改leader投票规则
      • 只投标给log index、termid跟自己相同的candidate,比自己大的不行,例如上个周期内,三分之一的index为10,三分之一为9,三分之一为11,那么下个周期的选举可能分裂,没人能得到多数派选票。
      • 只投标给log index、termid比自己大的candidate,相等的不投,选举也会分裂,比如上个周期内,三分之二的index位10,三分之一为9,那么这个规则也不会有人赢得选举
      • 因此为了liveness,只能投给跟自己相同或者比自己大的。
      • 在一个leader的recovery过程中,commit index的更新,只能依赖本leader周期内新发布的log多数派来判断,如果非本leader任期内的log,可能会成为非法的log,这一点有点难以理解,不过作者的论文中有一个case描述。

你可能感兴趣的:(raft比较容易混淆的问题)