论文地址:Raft搁置:我们拥有真正的共识么
在查看了Viewstamped复制(和VRR)、Paxos、Zookeeper的原子广播和Raft之后,我们即将结束这段旅程。并不是说我们已经用尽了所有关于这些主题的文献——远远没有!但我们确实耗尽了我的大脑:)。这些都是很难批判性地阅读的论文,也很难提供简明的总结——每一个小细节往往对正确的操作至关重要。当然Raft的一个要点是减少这种认知过载,也是Howard等人的目标之一。就是复制Raft的工作,看看这是不是真的。
希望你对这些算法的工作原理以及它们的共同点有一个了解。你还可以学习内燃机的基本原理。但你会因此决定自己制造汽车引擎是个好主意吗?内燃机如何工作的理论和现代汽车发动机的制造实践之间有很大的差距。通过这些论文得出的主题之一是,建立生产质量共识引擎是困难的。而那些“显而易见”的性能优化,你很可能会顺其自然,这几乎肯定不是一个好主意(除非你用与原始协议相同的严格程度来验证它们)。错误可能非常微妙,并且只发生在具有多个故障级别的深层系统跟踪中。
一致性是分布式系统设计的核心,当它出错时,坏事就会发生。在关于软件工程是否真的可以证明“工程”标签的争论中,这是一个需要真正的工程纪律的案例。您真的希望使用一个已经正式建模的算法,并证明其重要特性(Raft是在TLA+中建模的)。任何你想要进行的后续优化都需要根据这个模型进行验证——很容易做出一个“无辜”的改变,并发现你在某个方面打破了一个微妙的假设。模型检查程序可以探索允许的系统跟踪,以清除深层和细微的错误。然后,您需要测试您的实际实现,以确保它忠实地遵循建模的系统,并捕获现实世界中发生的任何问题。或者,您可以使用满足所有这些条件的一致性库,并在上面插入状态机…
在Raft中的Howard等人。表现出这种严谨。在这里,我们找到了Raft的一个独立实现来评估它的易懂性和原始规范的完整性;一个用于复制性能结果和探索场景的完整分布式系统模拟器;以及一个状态调用策略语言(Statecall Policy Language,SPL)中的形式化模型,用于验证系统的10000多个跟踪。源代码也在麻省理工学院的许可下提供:
我们的源代码在MIT许可证下,以开源软件的形式提供,网址是https://github.com/heidi-ann/ocaml-raft,标签是v1.0,可以通过OPAM包管理器安装为raft sim.1.0。所使用的数据集也可以在:https://github.com/heidi-ann/ocaml-raft-data上获得,也标记为v1.0。
本文对Raft协议做了一个很好的总结,但是我们可以跳过昨天的覆盖Raft协议。这个项目是用OCaml编写的。
我们选择OCaml作为复制的实现语言(与原始实现的C++相比),因为它的静态类型和强大的模块系统。核心协议的实现是纯的,不包含任何副作用代码,并且使用代数数据类型将协议的行为限制为其自身的安全标准。当静态类型系统不足时,我们可以自由地使用断言检查来限制运行时行为。
通过在SPL中建模Raft的状态转换,可以使用模型检查工具,还可以生成OCaml代码,在运行时充当安全监视器:
Raft的状态转换模型(如图3)用Statecall策略语言(Statecall Policy Language,SPL)编码。SPL是用于指定非确定性有限状态自动机(NFA)的一阶命令式语言。我们选择使用SPL是因为它能够编译成Promela,用于SPIN中的模型检查,或者编译成OCaml,在运行时充当安全监视器。SPL的替代方案包括使用MoDist这样的系统,该系统直接检查协议实现,或者直接在Promela中对模型进行编码,就像最近对Paxos所做的那样。
模拟器也是用OCaml构建的。在模拟中,可以对集群状态有一个整体的视图来帮助验证。
为了评估Raft协议在各种网络环境中的实现,我们还用OCaml构建了一个消息级的网络仿真框架。除了评估协议的性能之外,我们还可以使用模拟跟踪来捕获实现或协议规范中的细微错误。由于此类问题可能很少发生(例如10000次协议运行一次),快速模拟器提供了通过模拟跟踪分析解决这些问题的独特机会。此外,我们可以使用模拟器对集群的整体视图来确保所有节点对分布式系统的视图都与协议一致。为了满足这些特定领域的需求,我们设计了自己的仿真框架,而不是选择传统的事件驱动网络模拟器,如ns3或OMNeT++。
利用该模拟器,作者能够再现原始Raft的性能结果。“然后,通过复制作者最初的实验设置来校准我们的模拟,我们能够使用我们的框架快速地对协议进行原型优化。”
如果使用两个单独的计时器,并且将候选超时设置为低于跟随者超时,则选举的进行速度将更快,而不是将单个计时器同时用于跟随者和候选超时。在高度竞争环境的模拟下,这导致在281毫秒内建立领导者,而在1330毫秒内没有优化。
对被多数Leader否决的候选人的二元指数退选也会缩短选举时间。然而,将其与较低的候选计时器结合使用比单独使用较低的候选计时器性能稍差。
对于客户机命令完成,存在一种按比例尾随效应,少数异常值(最常见的情况是当一个领导失败,随后选出一个新的领导)比正常情况花费的时间要长得多。客户端提交超时值通常设置得比RTT高得多,以适应这种情况。引入单独的ClientCommit确认将允许使用两个不同的计时器来分离正常和选举情况。
使用SPL检查模拟痕迹,在任何情况下都不会影响安全保证。
然而,我们确实在一些模拟跟踪中观察到了永久性的livelock,这是由于额外的承诺条件(详见第2.3.3节)和我们放置客户机请求缓存之间的交互所导致的。我们建议,如果一个客户机请求被额外的提交条件阻止,则leader应该在其日志中创建一个no-op条目,并在集群中复制该条目。我们请读者参阅我们的技术报告,以详细分析这一问题。
(“额外的承诺条件”是指新的Leader只有在成功地复制了当前术语的条目后,才能提交前一术语的条目)。
这就引出了一个大问题:Raft真的比其他选择更容易理解吗?
根据我们的经验,Raft的高级思想比Paxos更容易理解。然而,该协议仍然有许多微妙之处,特别是在处理客户端请求方面。迭代协议描述模块化并隔离了协议的不同方面,以便于读者理解,但在我们的经验中,这妨碍了实现,因为它引入了组件之间的意外交互(请参阅上一节)。与Paxos一样,原始文件的简洁性也将许多实现决策留给读者。其中一些遗漏,包括协议更微妙方面的详细文档和对作者设计决策的分析,在Ongaro关于Raft的博士论文中得到了纠正。然而,这只是在我们的努力接近尾声时才得到的。尽管如此,我们相信Raft已经实现了它的目标,成为一个比Paxos更容易理解的共识算法。