Q: 人们使用Raft来做什么?

A: Raft(和Paxos)最常用于构建容错的“配置服务”,其任务是跟踪在大型部署中服务器当前的责任分配情况。这项任务对于带有复制的部署特别敏感;基于Raft的配置服务通常用于以避免脑裂的方式选择主服务器。VMware FT的测试和设置服务器是配置服务的一个简单例子。Chubby、ZooKeeper和etcd是基于Raft或Paxos的更强大的容错配置服务;它们被广泛使用。

一些数据库,如Spanner、CockroachDB和Lab 3,使用Raft或Paxos来复制数据。(相比之下,GFS、VMware FT和链复制使用更简单的主备份进行数据复制。)一些数据库以两种不同的方式使用Raft或Paxos:用于分配服务器责任的配置服务(对于每个分片,谁是当前的主服务器以及谁是备份),以及分别处理每个分片内的数据。

Q: Raft为了简单性牺牲了什么?

A: Raft为了清晰而牺牲了一些性能;例如:

  • 每个操作必须写入磁盘以持久化;性能可能需要将许多操作批量写入每个磁盘写入。

  • 每个追随者只能有一个AppendEntries在从领导者飞往追随者的途中:追随者会拒绝顺序错误的AppendEntries,且发送者的nextIndex[]机制要求一次一个。为多个AppendEntries提供管道化会更好。

  • 快照设计只适用于相对较小的状态,因为它将整个状态写入磁盘。如果状态很大(例如,如果它是一个大数据库),你会希望有一种方式只写入最近变化的状态部分。

  • 类似地,通过发送完整快照来更新恢复的副本将会很慢,如果副本已经有一个只是稍微过时的快照,这是不必要的。

  • 服务器可能无法充分利用多核,因为操作必须一个接一个地执行(按日志顺序)。

这些可以通过修改Raft来解决,但结果可能作为教程的价值较少。

Q: Raft是否在现实世界的软件中使用,或者公司通常自己开发Paxos的变体(或使用不同的共识协议)?

A: 有几个现实世界中的Raft用户:Docker(https://docs.docker.com/engine/swarm/raft/)、 etcd(https://etcd.io)和MongoDB。据说其他使用Raft的系统包括CockroachDB、RethinkDB和TiKV。也许你可以从http://raft.github.io/开始找到更多。

另一方面,许多现实世界的状态机复制系统(Google的Chubby、ZooKeeper的ZAB)是从较老的Multi-Paxos和Viewstamped复制协议衍生出来的。

Q: Paxos是什么?在什么意义上Raft更简单?

A: Paxos是一种协议,允许一组服务器就单个值达成一致。虽然Paxos需要一些思考才能理解,但它比Raft简单得多。这里有一篇易于阅读的关于Paxos的论文:

http://css.csail.mit.edu/6.824/2014/papers/paxos-simple.pdf

然而,Paxos解决的问题比Raft小。要构建一个现实世界的复制服务,副本需要就一系列不确定的值(客户端命令)达成一致

,它们需要有效地恢复当服务器崩溃和重启或错过消息的方式。人们以Paxos为起点构建了这样的系统;查阅Google的Chubby和Paxos Made Live论文,以及ZooKeeper/ZAB。还有一个叫Viewstamped Replication的协议;它是一个好的设计,类似于Raft,但关于它的论文难以理解。

这些现实世界的协议是复杂的,(在Raft之前)没有一篇好的入门论文描述它们是如何工作的。相比之下,Raft论文相对容易阅读且相当详细。这是一个重大贡献。

Raft协议是否本质上比其他东西更容易理解并不清楚。这个问题被其他现实世界协议的好的描述缺乏所模糊。此外,Raft以多种方式牺牲性能以换取清晰;这对于教程来说是好的,但在现实世界的协议中并不总是可取的。

Q: Paxos存在多久了,然后作者们创建了Raft?

A: Paxos在1980年代末被发明。Raft大约在2012年开发。

Raft与一种叫做Viewstamped Replication的协议非常相似,最初发表于1988年。在1990年代初,基于Viewstamped Replication的复制容错文件服务器被构建,尽管没有在生产环境中使用。

一大批现实世界的系统是从Paxos衍生出来的:Chubby、Spanner、Megastore和Zookeeper/ZAB。从2000年代初开始,大型网站和云提供商需要容错服务,那时Paxos被重新发掘并投入生产使用。

Q: 在现实世界应用中,Raft的性能与Paxos相比如何?

A: 最快的Paxos衍生协议可能比论文中描述的Raft更快;看看ZAB/ZooKeeper和Paxos Made Live。另一方面,etcd3(使用Raft)声称比zookeeper和许多基于Paxos的实现实现了更好的性能(https://www.youtube.com/watch?v=hQigKX0MxPw)。

在某些情况下,Raft的领导者并不那么伟大。如果包含副本和客户端的数据中心彼此距离较远,人们有时使用来自原始Paxos的协议。原因是Paxos没有领导者;任何副本都可以开始一个协议;因此客户端可以与其本地数据中心的副本通信,而不必与远程数据中心的领导者通信。ePaxos是一个例子。

Q: 为什么我们要学习/实现Raft而不是Paxos?

A: 我们在6.824中使用Raft是因为有一篇论文清楚地描述了如何使用Raft构建一个完整的复制服务。我不知道有满意的论文描述如何基于Paxos构建一个完整的复制服务器系统。

Q: 是否有像Raft这样的系统,当集群中的少数成员处于活动状态时也能生存并继续运行?

A: 不可能具有Raft的属性。但是你可以在不同的假设下或不同的客户端可见语义下做到这一点。基本问题是脑裂——由于多个副本集群中的多个子集在彼此不知情的情况下更改状态,导致多个发散的状态副本的可能性。我知道的有两种解决方法。

如果某种方式客户端和服务器

可以准确地了解哪些服务器是活动的,哪些是死亡的(而不是活着但由于网络故障无法到达),那么可以构建一个系统,只要一个服务器是活着的,它就可以运行,选择(例如)已知存活的服务器中编号最低的服务器。然而,一个计算机通常不可能决定另一个计算机是否死亡,而是因为网络丢失了它们之间的消息。一种做法是让人类来决定:人类可以检查服务器并决定哪些是活着的,哪些是死亡的。

另一种方法是允许脑裂操作,并且在分区愈合后有一种方式让服务器协调结果发散的状态。这对于某些类型的服务是可行的,但具有复杂的客户端可见语义(通常称为“最终一致性”)。看看分配给课程后期的COPS、FuzzyLog和比特币论文。

Q: 在Raft中,正在进行选举过程中,被复制的服务对客户端不可用。实际上这会造成多大的问题?

A: 客户端可见的暂停可能大约在十分之一秒的数量级。作者期望故障(因此选举)是罕见的,因为它们只发生在机器或网络失败时。许多服务器和网络连续运行数月甚至数年,所以这对许多应用程序来说似乎不是一个巨大的问题。

Q: 是否有其他共识系统在没有领导选举暂停的情况下运行?

A: 有基于Paxos的复制版本没有领导者或选举,因此不会在选举期间遭受暂停。没有领导者的代价是每次协议需要更多的消息。

Q: Raft和VMware FT之间的关系是什么?

A: Raft没有单点故障,而VMware FT在测试和设置服务器的形式中确实有单点故障。在这个意义上,Raft在本质上比VMware FT更具容错性。可以通过使用Raft或Paxos实现FT的测试和设置服务器作为复制服务来解决这个问题。

VMware-FT可以复制任何虚拟机客户端,因此可以复制任何服务器风格的软件,即使是那些不知道自己正在被复制的软件。Raft被用作集成到应用软件中的库,通常被专门设计为与复制工作良好。

Q: 为什么恶意人士无法接管Raft服务器,或伪造不正确的Raft消息?

A: Raft不包括防御这类攻击的措施。它假设所有参与者都遵循协议,并且只有正确的服务器集在参与。

真正的部署需要排除恶意攻击者。最直接的选择是将服务器放在防火墙后面,以过滤来自互联网上随机人员的数据包,并确保防火墙内的所有计算机和人都是值得信赖的。

可能存在Raft必须在潜在攻击者相同的网络上操作的情况。在这种情况下,一个好的计划是用某种加密方案对Raft数据包进行认证。例如,给每个合法的Raft服务器一个公钥/私钥对,让它对发送的所有数据包进行签名,给每个服务器一个合法Raft服务器的公钥列表,并让服务器忽略没有用列表上的密钥签名的数据包。

Q: 论文提到Raft

在所有非拜占庭条件下都有效。什么是拜占庭条件,它们为什么会导致Raft失败?

A: “非拜占庭条件”意味着服务器是停止故障:它们要么正确地遵循Raft协议,要么停止。例如,大多数电源故障是非拜占庭的,因为它们导致计算机停止执行指令;如果发生电源故障,Raft可能会停止运行,但它不会向客户端发送错误的结果。

拜占庭故障指的是一些计算机执行不正确的情况,因为存在错误或有人恶意控制计算机。如果发生这样的故障,Raft可能会向客户端发送错误的结果。

6.824的大部分内容是关于容忍非拜占庭故障。尽管拜占庭故障的正确操作更困难;我们将在学期末触及这个主题。

Q: 假设Raft集群是在同一物理位置配置的,还是可以在地理分布的数据中心部署对等点?

A: 典型的部署是单个数据中心。我们稍后将看到一些系统跨数据中心运行Paxos(例如,Spanner),这最好是通过无领导者设计完成的,这样客户端可以与本地对等点(而不是潜在的遥远领导者)通信。

Google的Chubby论文报告说,他们的Chubby部署通常是单个数据中心,除了根Chubby(跨地理分隔的数据中心)。(Chubby不是基于Raft,而是使用基于Paxos的Google复制状态机库。)

Q: 是否有不需要严格操作顺序的Raft共识算法的变体?(即,它们不必遵循领导者完整性属性。)

A: 如果你知道操作是否可交换,则可以。Google“generalized paxos”或“exploiting commutativity for practical fast replication”。

Q: 在图1中,客户端和服务器之间的接口是什么样的?

A: 通常是对服务器的RPC接口。对于像你在Lab 3中将要构建的键/值存储服务器,它是Put(key,value)和Get(value) RPCs。RPCs由服务器中的键/值模块处理,该模块调用Raft.Start()要求Raft将客户端RPC放入日志中,并读取applyCh以了解新提交的日志条目。

Q: 如果客户端向领导者发送请求,但领导者在将客户端请求发送给所有追随者之前崩溃了,新领导者的日志中没有该请求怎么办?这不会导致客户端请求丢失吗?

A: 是的,请求可能会丢失。如果日志条目未提交,Raft可能不会在领导者更换期间保留它。

这是可以的,因为如果Raft没有提交请求,客户端不可能收到对其请求的回复。客户端会知道(通过看到超时或领导者更换)其请求可能已丢失,并将重新发送它。

客户端可以重新发送请求的事实意味着系统必须防范重复请求;你将在Lab 3中处理这个问题。

Q: 如果出现网络分区,Raft是否会出现两个领导者和脑裂?

A: 不会。最多只能有一个活跃的领导者。

只有当它可以通过RequestVote RPCs与大多数服务器(包括自己)联系时,新领导者才能被选举出来。因此,如果存在分区,并且其中一个分区包含

大多数服务器,那么该分区可以选举出新的领导者。其他分区必须只有少数,因此它们不能选举出领导者。如果没有多数分区,将没有领导者(直到有人修复网络)。

Q: 假设在网络分区时选举出了新领导者,但旧领导者在不同的分区中。旧领导者将如何知道停止提交新条目?

A: 旧领导者要么无法获得其AppendEntries RPCs的多数成功响应(如果它在少数分区中),或者如果它可以与多数人交谈,那么多数人必须与新领导者的多数人重叠,而重叠中的服务器将告诉旧领导者有更高的任期。这将导致旧领导者转为追随者。

Q: 当一些服务器已经失败时,“多数”是指活着的服务器的多数,还是所有服务器(即使是死亡的)的多数?

A: 始终是所有服务器的多数。因此,如果总共有5个Raft对等点,但两个已经失败了,候选人仍然必须获得3票(包括自己)才能被选为领导者。

这有许多原因。可能是两个“失败”的服务器实际上在不同的分区中正常运行。从他们的角度来看,有三个服务器失败了。如果他们被允许仅使用两票(来自看起来活着的两个服务器)选举出领导者,我们会得到脑裂。另一个原因是我们需要任何两个领导者的多数在至少一个服务器上重叠,以保证新领导者看到前一个任期的编号和在前任期中提交的任何日志条目;这需要所有服务器的多数,无论是死是活。

Q: 如果选举超时太短会怎样?这会导致Raft出现故障吗?

A: 选举超时的不良选择不影响安全性,它只影响活性。

如果选举超时太小,那么追随者可能会在领导者有机会发送任何AppendEntries之前反复超时。在这种情况下,Raft可能会将所有时间都花在选举新领导者上,而没有时间处理客户端请求。如果选举超时太大,那么在领导者失败后选举新领导者之前将有不必要的长暂停。

Q: 为什么要随机化选举超时?

A: 为了减少多个对等点同时成为候选人并在它们之间分散投票,以至于没有人获得多数的机会。

Q: 候选人一旦从多数人那里收到投票,就可以宣布自己为领导者,而不用等待进一步的RequestVote回复吗?

A: 是的——多数人足够。等待更长时间将是一个错误,因为一些对等点可能已经失败,因此永远不会回复。

Q: Raft假设什么网络?

A: 网络是不可靠的:它可能会丢失请求和回复,并延迟它们。Raft的RPC库不提供可靠性;它是最佳努力的(例如,它发送一个请求,但网络可能会丢弃它)。实验室的RPC库提供类似的语义:它可能会丢失请求,丢失回复,延迟消息,并完全断开特定主机的连接。

Q: 在requestVote RPC中检查v

otedFor的目的是什么?

A: 两个候选人可能同时为同一个新任期开始选举。一个追随者应该只为他们中的一个投票。

Q: 领导者除了崩溃之外还能停止成为领导者吗?

A: 是的。如果领导者的CPU慢,或其网络连接断开,或丢失了太多数据包,或数据包传输太慢,其他服务器将不会看到其AppendEntries RPCs,并将开始选举。

Q: 追随者的日志条目何时发送到它们的状态机?

A: 只有在领导者说条目已提交时,使用AppendEntries RPC的leaderCommit字段。在那时,追随者可以执行(或应用)日志条目,对我们来说意味着在applyCh上发送它。

Q: 领导者应该等待AppendEntries RPC的回复吗?

A: 领导者应该并发发送AppendEntries RPC,而不等待。当回复回来时,领导者应该计数,并且只有当它从大多数服务器(包括自己)那里获得回复时,才标记日志条目为已提交。

在Go中做到这一点的一种方式是让领导者在单独的goroutine中发送每个AppendEntries RPC,这样领导者就可以并发发送RPCs。

Q: 如果一半(或更多)的服务器死亡会怎样?

A: 服务不能取得任何进展;它会不断尝试选举领导者。如果/当足够多的服务器带着持久的Raft状态恢复生机时,它们将能够选举出领导者并继续。

Q: 为什么Raft日志是1索引的?

A: 你应该将它视为零索引的,但是从一个具有0任期的条目(在index=0处)开始。这允许第一个AppendEntries RPC包含0作为PrevLogIndex,并且是日志中的有效索引。

Q: 当网络分区时,少数分区中的客户端请求是否会丢失?

A: 只有拥有服务器多数的分区可以提交和执行客户端操作。少数分区中的服务器将无法提交客户端操作,因此它们不会回复客户端请求。客户端将继续重新发送请求,直到它们可以联系到多数Raft分区,因此这些客户端的请求不会永远丢失。

Q: 5.4.3中的论证是否是完整的证明?

A: 5.4.3不是完整的证明。这里有一些可以查看的地方:

http://ramcloud.stanford.edu/~ongaro/thesis.pdf
http://verdi.uwplse.org/raft-proof.pdf

Q: 是否有任何限制可以构建在Raft之上的应用程序?

A: 我认为为了干净地适应像Raft这样的复制状态机框架,复制服务必须是自包含的——它可以有私有状态,并接受来自客户端的更新状态的命令,但它不能在没有特殊预防措施的情况下与外部实体联系。如果复制应用与外部世界互动,外部世界必须能够正确处理重复请求(由于复制和日志在重启后的重放),并且它必须永远不会自相矛盾(即,它必须小心地

向所有副本发送完全相同的答案,并对日志条目的所有重新执行)。这反过来似乎要求任何Raft基础应用联系的任何外部实体本身必须是容错的,即可能必须使用Raft或类似的东西。这相当限制。

例如,想象一个复制的在线订购系统向某个外部信用卡处理服务发送信用卡充电请求。那个外部处理器将看到重复的请求(每个副本一个或多个)。它会对每个请求做出完全相同的响应吗?它会多次收费吗?如果它确实做了正确的事情,那么在不恰当的时间崩溃和重启时它仍然会做正确的事情吗?

Q: 为什么叫做Raft?

A: https://groups.google.com/g/raft-dev/c/95rZqptGpmU