最近,我更深入地研究了分布式系统领域中的一个重要算法RAFT。RAFT是一种共识算法,这意味着它旨在促进一组计算机就世界状态达成一致(更多关于稍后如何表示世界状态的确切信息),即使在这组计算机之间的通信中断时(例如,有人意外拔下了将某些节点连接到大多数节点的网线)。
在许多现代系统中都需要可靠地跨多台计算机存储世界状态、保持状态同步以及扩展此功能的问题例如,Kubernetes将所有集群数据存储在etcd中,etcd是一个在幕后使用RAFT的键值存储库。
考虑到算法的重要性(和细微差别),我想首先尝试将其归结为最简单的组件,然后再深入研究。
值得注意的是,关于木筏的资源非常丰富。我最喜欢的一些是:
麻省理工学院6.824课程的实验2,该课程提供了完整的测试套件和关于如何在可管理的块中实现算法的指导。
如上所述,RAFT是一种算法,旨在帮助计算机通过一个称为共识的过程来同步状态,尽管它不是第一个设计这样做的系统。
RAFT和以前的共识算法的一个主要区别是希望在头脑中保持简单性来优化设计-作者认为现有研究缺少这一特征。
特别是,RAFT的目标是改进Paxos,Paxos是一种开创性的但(RAFT的作者认为)实现分布式共识的一套有点复杂的想法。
为了量化Paxos的复杂性,RAFT的作者在NSDI进行了一项调查,NSDI是分布式系统学者的顶级会议之一:
在对NSDI 2012与会者的非正式调查中,我们发现几乎没有人对Paxos感到满意,即使是在经验丰富的研究人员中也是如此。我们自己也在与Paxos作斗争;我们直到阅读了几个简化的解释并设计了我们自己的替代协议后,才能够理解完整的协议,这一过程花了将近一年的时间。
其他工程师也记录了生产Paxos的困难。谷歌在帕克索斯的基础上实现了一个名为Chubby的系统,并记录了“算法和工程挑战”(Algorithm and Engineering Challenges…。在将帕克索斯从理论转化为实践的过程中遇到的问题。在他们的论文中,他们指出,“尽管有关于这个主题的现有文献[Paxos],但由于各种原因,建立一个生产系统被证明是一项不平凡的任务”。
从上面的评论中可以看出,Paxos似乎是一组极其复杂且几乎不可能实现的想法,尽管这并不完全正确。一些人认为,RAFT用不稳定来换取业绩打击,尽管考虑到最新的etcd基准,目前尚不清楚这是否属实。为了进一步阅读Paxos vs RAFT,这篇文章是一篇有趣的读物。
现在我们有了一些关于为什么的背景信息?关于筏子,有几个关于筏子的高级要点是很重要的:
RAFT算法的目的是跨计算机群集复制世界状态。RAFT共识不是发送包含世界完整状态的单一消息,而是涉及增量更改的日志,在内部表示为一组命令。键值存储可以用作以这种方式表示世界状态的更具体的示例-KV存储中的世界的当前状态包含这些键的键和值,但是每次PUT或DELETE都是导致该状态的单个更改。这些单独的更改可以以仅附加的日志格式存储(本系列的第2部分在RAFT日志和复制一节中更详细地介绍了RAFT的日志组件是如何工作的)。
RAFT对等点使用定义明确的消息进行通信。在最初的论文中有几个定义,但两个基本的是:RequestVote:RAFT用来选举协调更新世界状态的对等体的消息。更多信息请参见第2部分的领导人和领导人选举部分。
AppendEntries:RAFT使用的一条消息,允许对等方就世界状态的变化进行通信。有关如何复制状态的更多详细信息,请参阅RAFT日志和复制部分。
RAFT集群的成员被称为对等体,并且可以处于三种状态之一:领导者:协调集群中的其他节点以更新其状态的节点。所有对世界状态的改变都是通过领导者来实现的。
跟随者:节点正在从引导者那里接收有关如何更新其状态的指令。
领导者通过采取两种类型的操作来管理对世界状态的更新:提交和应用。一旦网络中的大多数节点确认它们也成功地存储了条目,领导者就会在其日志中提交索引(称为CommitIndex)。当一个节点在日志中向前移动其提交索引时(提交索引只能向前移动,而不能向后移动!),它会将日志中的条目应用(处理)到提交的位置。提交和应用的想法确保了Leader不会更新其世界状态,直到确保导致该状态的日志是不可能更改的-在下一篇文章的安全部分中提供了关于“不可能更改”的更多信息。
有了这样的背景,我们可以开始将木筏分解成更具体的部分,试图回答有关协议的问题:
领导人和领导人选举包括如何协调Raft群集状态的更新:哪台计算机正在协调世界状态的变化,这台计算机如何与RAFT群集中的其他计算机协调,以及计算机协调多长时间?
RAFT日志和复制涵盖了状态被复制的机制:世界的状态如何传播到集群中的其他计算机?如果其他计算机断开了连接,但现在又恢复了联机,那么它们如何获得有关世界状态的新信息(有人拔下了计算机的以太网电缆)?
安全涵盖了RAFT如何防范可能破坏世界状态的边缘情况:我们如何确保一台具有旧世界状态的计算机不会意外覆盖另一台计算机的最新世界状态?
鉴于本文已经相当长,我将上面概述的三个主题保留到本系列的第二部分(可在此处获得)。