对Raft协议的一些思考

https://zhuanlan.zhihu.com/p/51358042

什么一致?

一致性协议都是为了保证所有的节点状态是一致的,而一致的日志输出到状态机就可以产生一致的状态,所以只需要保证日志是一致的。

怎么保证?

简化问题

首先明确一下适用的场景:异步网络通信环境,非拜占庭错误。设想一种理想情况,没有节点宕机和网络分区发生。这样保证起来就会很简单,所有的请求都发给leader,leader把日志都同步给follower后,将日志提交到状态机。由于所有的follower都是复制的同一个leader的日志,自然大家都是一致的。然而现实情况不会这么完美,在分布式系统中节点宕机,网络分区是常态,所以我们要解决可能出现的问题。

现实情况下会出现什么问题

  1. leader出故障了
  2. follower出故障了
  3. 网络分区了

下面分别阐述Raft是怎么解决这三个问题的

1.leader出故障了

这是最复杂的情况,会影响选主和日志的同步

选主

由于我们在上面说的理想情况下,follower都是复制的leader的日志,所以我们必须保证集群中任何时刻都存在leader,并且期望有且只有一个,因为leader大于1个时,日志就出现冲突了。 当leader出故障时,必然就需要重新选一个leader,所以Raft就设计了选主的算法,具体算法直接看论文就可以了。这里提出几个问题:
1. 为什么要设置任期号?
任期号在Raft中(以及其它的一些一致性协议中)非常重要,它其实代表了当前节点的状态是否足够新,因为我们总是认为新的更为准确。在分布式环境中,节点可能会收到彼此冲突的消息,那选哪个呢,就选任期号大的,所以在发动选举时,就会将任期号加一来保证新的leader会被识别为更新的。
2. 什么时候leader会大于1个,怎么处理?
当网络分区时,就可能出现leader大于1个的情况,普通的网络分区比较简单,比如A,B和C,D,E出现了分区。这里讨论一种稍微复杂的情况,比如当前有A,B,C,D,E五台机,A为leader,此时A和B二者的网络出现分区,但是A,C,D,E以及B,C,D,E都可以正常通信,由于B超过一定时间没有收到leader的心跳,这时候B的term+1,发起新的选举,然后分两种情况:1.在B选举之前,A向C,D,E写了新的日志,那这时候B的日志不是最新的,选举永远不会成功,相当于此时集群中A,C,D,E会正常对外服务,leader不变 2.在B选举之前,A没有写新的日志,由于B的term更大,所以C,D,E会投票给B,这时候B成为新的leader,在此刻集群中出现了A,B两个leader,但A发出的请求不会被多数派通过(因为C,D,E的term更大),所以对外是一致的。所以即使出现了两个leader,Raft也可以保证确定log的时候不会有冲突。但有一个问题是,A在向C,D,E发心跳包的时候,从响应中可以知道自己的term落后了,就降为follower。然后,A也有可能再按照B的方式发起选举,这样就周而复始不断选举,造成很大的网络开销,这个可以通过pre-vote解决。

日志同步

论文列举了几种leader和follower的日志不一致的情况,但除了(a),本质原因都是由于这个follower以前是leader,当有未提交的日志时挂了,等恢复成follower的时候,就跟当前的leader日志不一致了。当出现不一致时,Raft采取的做法是用Leader的日志覆盖Follower的日志。这里提出几个问题:
1. 为什么leader将某个log entry设为commited之后,这个log entry之前的所有log,包括其他leader的log,都是可提交的? 
因为日志匹配特性,某个日志是commit,说明leader和大多数节点在这条日志以及这条日志之前的日志都是相同的,因此都是可以提交的。
2. leader完整特性怎么证明?有什么作用?
证明:虽然论文上的证明比较长,但可以由日志匹配特性直接得出leader完整特性,假设leader1不包含之前的某个leader2已经commit的日志,而如果这条commit的日志是最后一条日志,那这个leader1因为日志不够新不会赢得选举;如果这条日志 不是最后一条日志,那leader1的最后一条日志在被append的时候(那时候leader1还是follower),就会被当时的leader发现leader1中间缺失了一条commit日志,append就会失败。 
作用:由于每个leader都包含之前的term被commit的所有日志,就意味着不管leader怎么改变,已经commit的日志不会丢,所以输入到状态机的日志就是一致的,保证了状态机安全特性。 3. 为什么需要日志匹配特性?
日志匹配特性的目的有两个:一是为了得到leader完整特性,二是保证如果一个log entry可以commit了,那它之前的entry都是可以提交的。第二个目的让leader可以顺序的commit日志,进而状态机也可以顺序的apply日志,简化了处理逻辑。 假设我们可以放弃这两个目的(比如ParallelRaft),比如通过其他措施来保证leader完整特性和状态机的安全特性,那我们就可以放弃日志匹配特性,那follower每次AppendEntry的时候就不用等待前面的entry都Append,就可以提高系统的整体吞吐。

2.follower出故障了

只要出问题的follower小于总节点数量的一半,整个Raft Group就能正常工作。由于不一致时,follower会用leader的日志覆盖自己的,所以不管follower出什么问题,leader会对follower不断重试,只要在恢复时通过RPC将follower的日志恢复成leader的即可。

3.网络分区

网络分区可能会导致脑裂问题,在选主的第3个问题讨论了网络分区对选主的影响。同时,网络分区还可能会导致stale read, 可以通过ReadIndex Read和Lease Read的方法来解决,具体参考https://pingcap.com/blog-cn/lease-read/这篇文章。

Multi-Raft

数据量大的时候,单个Raft实例负载太高,为了提高整体吞吐,往往将数据分为多个片,每个片由独立的Raft Group来管理。会有一个类似于元数据服务器的东西来管理所有的Raft Group,负责数据的分片,Group间的负载均衡等,难点引用Elasticell-Multi-Raft实现这篇文章提到的:

1. 数据何如分片
2. 分片中的数据越来越大,需要分裂产生更多的分片,组成更多Raft-Group
3. 分片的调度,让负载在系统中更平均(分片副本的迁移,补全,Leader切换等等)
4. 一个节点上,所有的Raft-Group复用链接(否则Raft副本之间两两建链,链接爆炸了)
5. 如何处理stale的请求(例如Proposal和Apply的时候,当前的副本不是Leader、分裂了、被销毁了等等)
6. Snapshot如何管理(限制Snapshot,避免带宽、CPU、IO资源被过度占用)

具体可以参考上面这篇文章看看他们是怎么解决这些问题的

ParallelRaft

这是在阿里的PolarFS中提出的对Raft在高I/O场景下的一种改进。具体来说就是Follower可以乱序确认,leader可以乱序提交,状态机可以乱序应用。
乱序确认是指Follower可以不管日志匹配特性,直接确认,所以我认为面向云数据库,超低延迟文件系统PolarFS诞生了这篇文章中提到的ParallelRaft继承了Raft的LogMatching特性应该是有问题的,因为如果是乱序确认是没法满足LogMatching的。但是日志匹配特性的不满足就会导致leader完整特性的不满足,所以ParallelRaft用了另外的手段来满足leader完整特性,就是在leader选举的时候将leader中的log空洞给补上,这里感觉和multi-paxos很像。日志匹配特性的不满足还会带来的另一个问题就是一个entry变为commited之后,并不代表它之前的entry都可以commit了,因此leader的提交注定也是乱序的。状态机这里接收到一个log entry,如果发现它之前的entry不在的话当然可以一直等,直到把空洞补齐。但ParallelRaft采用了一种叫look behind buffer的数据结构来提高apply entry的并行度,每个log entry都记录自己前面的N个entry的修改情况(follower接收到的entry是乱序的,但leader生成entry的时候肯定是有序的,所以leader在生成一个entry的时候肯定知道了它前面的N个enty的修改情况)。look behind buffer记录每个entry修改的LBA(逻辑块地址),如果修改的块有重叠就代表有冲突,就需要等待,否则就可以乱序执行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值