quyilie 2019-06-27
Raft是当前分布式领域最重要的一致性算法之一,今天我们就来好好研究研究这个算法的论文, 还有对应网站, 动画, 不想看英文的也有中文的翻译,所以我这边就不翻译了,主要还是记录一下论文重点和自己的心得。
Raft算法作者的初衷是对标Paxos算法(过去十年分布式一致性的事实标准),但是要比它更易理解,主要手段有:
Raft使用了更强的Leader,感觉这和我之前看的OceanBase是相似的,就是增强Leader(UpdateServer)或者说单点的作用,加重中心化(这也是社会的运作方式,没有Leader就是大家一盘散沙,文明是达不到今天这个程度的),要做决策就先选择一个Leader,然后让他去协调所有的决议,会更加简单快速,而Paxos就是P2P或者说弱Leader的方式。事实上,我们之所以使用分布式系统也是迫不得已,如果单台机器能搞定还要这么多系统干嘛?所以我们也要看到单点系统的好处,那就是一致性很容易保证,所以在分布式系统中使用一个增强(能力和责任)的单点既利于一致性的保证也能获得分布式的优势。
Leader全权负责管理日志复制,从而实现一致性,所以有了Leader这一机制,一致性问题就可以被分解为上述三大方面了,下面分别说明。
Term number
最大和先来先服务原则可以使得每一个 Term 内最多有一个 Leader(如果没有 Leader 就会超时进入下一个 Term 进行新的选举)。Leader 保持身份并阻止其他节点成为 Leader 的方法是不停地向其他节点发送心跳消息(也可以包含需要复制的日志)。如果 follower 或者 candidate 崩溃了,那么后续发送给他们的请求都会失败。Raft 中处理这种失败就是简单的通过无限的重试,因为Raft的这种请求都是幂等的,所以这样重试不会造成任何问题。比如,一个follower如果收到附加日志请求但是他已经包含了这一日志,那么他就会直接忽略这个新的请求。
Leader 选举是 Raft 中对时间要求最为关键的方面。只要系统满足下面的时间要求:
广播时间(broadcastTime) << 选举超时时间(electionTimeout) << 平均故障间隔时间(MTBF)Raft 就可以选举并维持一个稳定的Leader。当Leader崩溃后,整个系统会大约相当于选举超时的时间里不可用,广播时间和平均故障间隔时间是由系统决定的,但是选举超时时间是我们自己选择的, Raft的请求 要接收方将信息持久到存储中去,所以广播时间大约是 0.5 毫秒到 20 毫秒,取决于存储的技术。因此,选举超时时间可能需要在 10 毫秒到 500 毫秒之间。大多数的服务器的平均故障间隔时间都在几个月甚至更长,很容易满足时间的需求。
对于客户端来说,只要得到leader的ok回复就可以认为操作成功了,未得到ok(失败或超时)就需要重试。那么Raft是怎么保证这个语义的呢?
Leader未把日志未复制过半就挂了那么此次请求客户端肯定会知道是失败的,没影响;Leader把日志复制过半但是未回复ok就挂了的话,这些日志之后可能被提交也可能被覆盖,这就需要客户端带上唯一请求id重试,新的leader发现该id已经在日志中出现并且可被提交就直接回复ok,否则就重新执行一次这个请求;leader回复ok但是未提交就挂了的话,依赖于old entry的提交机制,这个请求还是能被落盘的。
通过这三个阶段不同的应对机制保证了ok的语义。
Raft也是能够应对脑裂问题的,比如ABCDE5个节点,A是leader,一开始保证正确的同步,某时刻,假设A没发出心跳给B(比如太忙)或者B没收到心跳(比如分区)使得B超时:
所以要么是避免脑裂选主,要么是脑裂后老leader自动降级为follower。脑裂问题就可以这样被解决了。当然最好的办法还是在节点之前加一个专线,降低分区的概率。
集群状态切换通过一个共同一致(新老配置的结合)的中间状态转换实现,这样基于两阶段的做法可以使得集群平滑地进行状态迁移。这一块没仔细看,不过 etcd 等 raft 实现都是采用了更加简洁和安全的一次只能变更一个节点的 single Cluser MemberShip Change 算法。
阅读原文:Mageekchiu