6.824 讲座6:raft(2)
回顾:
键/值服务为例,如实验3所示
目标:多机看起来和单机一样
目标:尽管有少量故障/断开服务器,但仍可用 高可用
提防网络分裂和裂脑!
[图:客户,k / v层,k / v表,筏层,筏日志]
[客户端RPC-> Start()->多数提交协议-> applyCh]
“状态机”,应用程序,服务
一些提醒:
领导者在多数回复AppendEntries之后提交/执行
领导者告诉对执行者的提交,执行(==在applyCh上发送)
为什么只等待大多数?为什么不等待所有同行?
即使少数群体崩溃了,可用性也可以保障
为什么多数就足够了?
任何两个majority重叠
因此,继任的领导人的majorities至少有一个peer重叠
因此,保证下一位领导者可以看到前任领导者提交的任何日志条目
它是所有同龄人中的大多数(死者和活着的),而不仅仅是大多数peer
***主题:raft日志(实验2B)
只要领导者待着:
客户只与领导者互动
客户不受追随者行为的影响
换领导才能使事情变得有趣
例如在老领导人失败之后
如何在没有客户看到异常的情况下更换领导者?(无缝操作)
过时的读取,重复的操作,丢失的操作,不同的顺序,&c
我们要确保什么?
如果任何服务器在日志条目中执行给定命令,
然后没有服务器对该日志条目执行其他操作
(图3的状态机安全性)
为什么?如果服务器不同意操作,则
更换领导者可能会改变客户可见的状态,
这违反了我们模仿单个服务器的目标。
例:
S1:put(k1,v1)| put(k1,v2)| …
S2:put(k1,v1)| put(k2,x)| …
不能同时执行它们的第二个日志条目!
崩溃后日志如何不一致?
领导者在将最后一个AppendEntries发送给所有人之前崩溃
S1:3
S2:3 3
S3:3 3
更糟糕的是:日志可能在同一条目中具有不同的命令!
在一系列领导者崩溃之后,例如
10 11 12 13 <-日志条目#
S1:3
S2:3 3 4
S3:3 3 5
通过让追随者采用新领导人的日志来强制达成raft协议
例:
S3被选为第六阶段的新负责人
S3发送带有条目13的AppendEntries
prevLogIndex = 12
prevLogTerm = 5
S2回复错误(AppendEntries步骤2)
S3将nextIndex [S2]减少到12
S3发送带有条目12 + 13,prevLogIndex = 11,prevLogTerm = 3的AppendEntries
S2删除其条目12(AppendEntries步骤3)
与S1类似,但必须再追溯一遍
回滚的结果:
每个实时关注者删除与领导者不同的日志尾
然后每个实时关注者在该点之后接受领导者的条目
现在关注者的日志与领导者的日志相同
问:为什么可以忘记S2的index = 12 term = 4条目?
新的领导者可以从上学期末回退提交的条目吗?
也就是说,新领导者的日志中是否可能缺少已提交的条目?
这将是一场灾难-老领导可能已经对客户说“是”
因此:raft需要确保当选的领导者具有所有已提交的日志条目
为什么不选择日志最长的服务器作为领导者?
例:
S1:5 6 7
S2:5 8
S3:5 8
首先,这种情况会发生吗?怎么样?
第六学期的S1组长;崩溃+重启;第七学期的领导者;崩溃并停下来
两次仅在附加到自己的日志后崩溃
下一个学期为8,因为S2 / S3中至少有一个在投票时获悉7
第8学期的S2负责人,只有S2 + S3活着,然后崩溃
所有同伴重启
谁应该成为下一位领导人?
S1的日志最长,但是条目8可能已提交!
因此新的领导者只能是S2或S3之一
即规则不能简单地是“最长日志”
5.4.1的末尾说明了“选举限制”
RequestVote处理程序仅对“至少最新”的候选人投票:
候选人在上一个日志条目中具有较高的任期,或者
候选人的上学期相同,时长相同或更长
所以:
S2和S3不会投票给S1
S2和S3将互相投票
因此只有S2或S3可以成为领导者,将迫使S1放弃6,7
好的,因为6,7的投票不是多数->未提交->没有回复给客户
->客户端将在6,7中重新发送命令
要点:
“至少最新”规则确保新领导者的日志包含
所有可能提交的条目
因此新的领导者将不会回滚任何已落实的操作
问题(上一讲)
图7,顶级服务器已死;哪个可以选?
根据图7中当选的领导者而定,不同的条目
最终将被提交或丢弃
c的6和d的7,7可被丢弃或提交
有些将始终保持承诺:111445566
如何快速回滚
图2设计为每个RPC备份了一个条目-太慢了!
实验室测试人员可能需要更快的回滚
论文概述了第5.3节末尾的方案
没有细节;这是我的猜测;更好的方案是可能的
S1:4 5 5 4 4 4 4
S2:4 6 6或4 6 6或4 6 6
S3:4 6 6 4 6 6 4 6 6
S3是第六学期的领导者,S1重获新生
如果关注者拒绝AppendEntries,则在回复中包括以下内容:
冲突条目中关注者的术语
该词的关注者首个条目的索引
如果领导者的日志条目带有跟随者的冲突术语:
将nextIndex [i]返回到领导者的最后一个条目以进行冲突
其他:
将nextIndex [i]移至关注词项的关注者的第一个索引
***主题:持久性(实验2C)
服务器崩溃后,我们希望发生什么?
木筏可以继续使用一台丢失的服务器
但我们必须尽快修复,以免跌破多数
两种策略:
替换为新的(空)服务器
需要将整个日志(或快照)传输到新服务器(缓慢)
如果永久失效,我们必须支持
或重新启动崩溃的服务器,以完整的状态重新加入,赶上
要求状态在崩溃之间持续存在
我们必须支持此功能,以便同时断电
让我们来谈谈第二种策略-持久性
如果服务器崩溃并重新启动,Raft必须记住什么?
图2列出了“持久状态”:
log [],currentTerm,votedFor
如果Raft服务器完好无损,则只能在重新启动后重新加入
因此必须将它们保存到非易失性存储中
非易失性=磁盘,SSD,电池供电的RAM和
每次更改后保存
在发送任何RPC或RPC答复之前
为什么登录[]?
如果服务器在提交条目中占领导者的多数,
必须记住,尽管重新启动,但任何未来的领导者
保证看到提交的日志条目
为什么投票?
以防止客户端投票给一位候选人,然后重新启动,
然后在同一(或更旧的!)任期内投票给其他候选人
可能导致两位领导人在同一任期内
为什么选择currentTerm?
确保只增加学期数
从过时的领导者和候选人中发现RPC
一些筏状态是易变的
commitIndex,lastApplied,next / matchIndex []
Raft的算法从初始值重建它们
持久性通常是性能的瓶颈
硬盘写入需要10毫秒,SSD写入需要0.1毫秒
因此持久性将我们限制为100到10,000个操作/秒
(另一个潜在的瓶颈是RPC,在LAN上花费<< 1毫秒)
许多技巧可以应对持久性缓慢:
每个磁盘写入批处理许多新的日志条目
坚持使用电池供电的RAM,而不是磁盘
崩溃+重新引导后,服务(例如k / v服务器)如何恢复其状态?
简单方法:从空状态开始,重播Raft的所有持久日志
lastApplied是易失性的,从零开始,因此您可能不需要额外的代码!
但是对于长寿命的系统来说,重播会太慢
更快:使用Raft快照并仅重播日志结尾
***主题:日志压缩和快照(实验3B)
问题:
日志将变得巨大-比状态机状态大得多!
重新启动或发送到新服务器将花费很长时间
幸运的是:
服务器不需要既完整的日志又服务状态
在状态中捕获日志的执行部分
客户只看到状态,而不是日志
服务状态通常要小得多,所以让我们保持
什么限制了服务器如何丢弃日志条目?
不能忘记未提交的条目-可能是领导者多数的一部分
不能忘记未执行的条目-尚未反映在状态中
要使其他服务器保持最新状态,可能需要执行条目
解决方案:服务定期创建持久的“快照”
[图:状态服务,磁盘快照,筏日志,筏持久]
执行特定日志条目时的整个状态机状态的副本
例如k / v表
服务将快照写入持久性存储(磁盘)
服务告诉Raft通过一些日志索引对其进行快照
筏在该索引之前丢弃日志
服务器可以随时创建快照并丢弃日志前缀
例如,当日志增长太长时
快照与日志的关系
快照仅反映执行的日志条目
因此只有提交的条目
因此服务器将只丢弃提交的日志前缀
任何未知的承诺将保留在日志中
因此,服务器的磁盘状态包括:
服务的快照,直到特定的日志条目
带以下日志条目的筏的持久日志
组合等效于完整日志
崩溃+重新启动后会发生什么?
服务从磁盘读取快照
木筏从磁盘读取持久日志
发送已提交但不在快照中的服务条目
如果追随者滞后并且领导者丢弃了追随者日志的末尾怎么办?
nextIndex [i]将备份到领导者日志的开始
因此领导者无法使用AppendEntries RPC修复该跟随者
因此,InstallSnapshot RPC
(问:为什么领导者不丢弃所有服务器具有的条目?)
InstallSnapshot RPC中有什么?图12、13
术语
lastIncludedIndex
lastIncludedTerm
快照数据
带InstallSnapshot的关注者做什么?
如果任期较旧则拒绝(不是当前领导者)
拒绝(忽略)是否关注者已经具有上一个包含的索引/词条
这是旧的/延迟的RPC
清空日志,替换为伪造的“ prev”条目
将lastApplied设置为lastIncludedIndex
用快照内容替换服务状态(例如k / v表)
请注意,状态和操作历史大致相同
设计师可以选择发送哪个
例如,滞后副本的最后几个操作(日志条目),
但丢失磁盘的副本的整个状态(快照)。
不过,副本修复可能非常昂贵,值得关注
问题:
收到的InstallSnapshot RPC可能导致状态机进入
时间倒退?也就是说,图13中的步骤8可能导致该状态
要重置的计算机,以使其反映较少的已执行操作?如果
是的,请解释如何发生。如果没有,请解释为什么不能
发生。
***主题:配置更改(实验室不需要)
配置更改(第6节)
配置=服务器集
有时候你需要
移至一组新服务器,或
增加/减少服务器数量
人工发起配置更改,由Raft管理
我们希望Raft能够正确应对配置更改期间的故障
即客户不应该注意(可能表现不佳)
为什么简单的方法不起作用?
假设每个服务器在当前配置中都有服务器列表
通过告诉每个服务器新列表来更改配置
在Raft之外使用某种机制
问题:他们将在不同的时间学习新的配置
示例:要用S4替换S3
我们告诉S1和S4新的配置是1,2,4
S1:1,2,3 1,2,4
S2:1,2,3 1,2,3
S3:1,2,3 1,2,3
S4:1、2、4
糟糕!现在两位领导人可以当选!
S2和S3可以选举S2
S1和S4可以选举S1
筏配置变更
想法:“联合共识”阶段,包括*新旧配置
避免新旧双方都可以独立选择领导者的任何时间
系统以Cold开头
系统管理员要求负责人切换到Cnew
木筏具有特殊的配置日志条目(服务器地址集)
每个服务器在其自己的日志中使用最后的配置
1.领导者对新的和冷的大多数人都做出新的承诺
2. Cold,new提交后,领导者将Cnew提交到Cnew中的服务器
如果领导者在此过程中的各个时刻崩溃了怎么办?
我们下一届可以有两名领导人吗?
如果可能发生,那么每个领导者都必须是其中之一:
A.在Cold中,但没有Cold,新的日志
B.在Cold或Cnew中,有Cold,new在日志中
C.在Cnew中,有Cnew在日志中
我们知道,按照通常的领导人选举规则,我们不能拥有A + A或C + C
A + B?不,因为B需要Cold和Cnew的多数
A + C?不,因为直到Cold才能继续进行Cnew,New致力于Cold
B + B?不,因为B需要Cold和Cnew的多数
B + C?不,因为B需要Cnew和Cold的多数
好!Raft可以切换到一组新服务器,而没有两个活跃领导者的风险
***主题:性能
注意:许多情况下不需要高性能。
键/值存储可能。
但GFS或MapReduce主站可能不会。
大多数复制系统具有类似的常见情况性能:
每个协议一个RPC交换和一个磁盘写入。
因此,Raft对于消息复杂性而言非常典型。
Raft做出了一些牺牲设计性能而简化设计的选择:
追随者拒绝乱序的AppendEntries RPC。
而不是在孔填充后保存使用。
如果网络大量重新排序数据包,则可能很重要。
没有提供批处理或流水处理AppendEntries的准备。
对于大状态而言,快照是浪费的。
慢的领导者可能会伤害raft,例如在地理复制中。
这些对性能有很大影响:
磁盘写入具有持久性。
消息/数据包/ RPC开销。
需要按顺序执行记录的命令。
只读操作的快速路径。
更注重性能的论文:
Zookeeper / ZAB;Paxos Made Live; Harp