Raft一致性算法(12)

 
在关于重新配置还有三个问题需要提出 。第一个问题是,新的服务器可能初始化没有存储任何的日志条目 。当这些服务器以这种状态加入到集群中,那么他们需要一段时间来更新追赶,这时还不能提交新的日志条目 。为了避免这种可用性的间隔时间,Raft 在配置更新之前使用了一种额外的阶段,在这个阶段,新的服务器以没有投票权身份加入到集群中来(领导人复制日志给他们,但是不考虑他们是大多数) 。一旦新的服务器追赶上了集群中的其他机器,重新配置可以像上面描述的一样处理 。
第二个问题是,集群的领导人可能不是新配置的一员 。在这种情况下,领导人就会在提交了 C-new 日志之后退位(回到跟随者状态) 。这意味着有这样的一段时间,领导人管理着集群,但是不包括他自己;他复制日志但是不把他自己算作是大多数之一 。当 C-new 被提交时,会发生领导人过渡,因为这时是最早新的配置可以独立工作的时间点(将总是能够在 C-new 配置下选出新的领导人) 。在此之前,可能只能从 C-old 中选出领导人 。
第三个问题是,移除不在 C-new 中的服务器可能会扰乱集群 。这些服务器将不会再接收到心跳,所以当选举超时,他们就会进行新的选举过程 。他们会发送拥有新的任期号的请求投票 RPCs,这样会导致当前的领导人回退成跟随者状态 。新的领导人最终会被选出来,但是被移除的服务器将会再次超时,然后这个过程会再次重复,导致整体可用性大幅降低 。
为了避免这个问题,当服务器确认当前领导人存在时,服务器会忽略请求投票 RPCs 。确切地说,当服务器在当前最小选举超时时间内收到一个请求投票 RPC,他不会更新当前的任期号或者投出选票 。这不会影响正常的选举,每个服务器在开始一次选举之前,至少等待一个最小选举超时时间 。然而,这有利于避免被移除的服务器扰乱:如果领导人能够发送心跳给集群,那么他就不会被更大的任期号废黜 。
7 日志压缩
Raft 的日志在正常操作中不断地增长,但是在实际的系统中,日志不能无限制地增长 。随着日志不断增长,他会占用越来越多的空间,花费越来越多的时间来重置 。如果没有一定的机制去清除日志里积累的陈旧的信息,那么会带来可用性问题 。
快照是最简单的压缩方法 。在快照系统中,整个系统的状态都以快照的形式写入到稳定的持久化存储中,然后到那个时间点之前的日志全部丢弃 。快照技术被使用在 Chubby 和 ZooKeeper 中,接下来的章节会介绍 Raft 中的快照技术 。
增量压缩的方法,例如日志清理或者日志结构合并树,都是可行的 。这些方法每次只对一小部分数据进行操作,这样就分散了压缩的负载压力 。首先,他们先选择一个已经积累的大量已经被删除或者被覆盖对象的区域,然后重写那个区域还活跃的对象,之后释放那个区域 。和简单操作整个数据集合的快照相比,需要增加复杂的机制来实现 。状态机可以实现 LSM tree 使用和快照相同的接口,但是日志清除方法就需要修改 Raft 了 。

Raft一致性算法

文章插图
 
 
图 12:一个服务器用新的快照替换了从 1 到 5 的条目,快照值存储了当前的状态 。快照中包含了最后的索引位置和任期号 。
 
图 12 展示了 Raft 中快照的基础思想 。每个服务器独立地创建快照,只包括已经被提交的日志 。主要的工作包括将状态机的状态写入到快照中 。Raft 也包含一些少量的元数据到快照中:最后被包含索引指的是被快照取代的最后的条目在日志中的索引值(状态机最后应用的日志),最后被包含的任期指的是该条目的任期号 。保留这些数据是为了支持快照后紧接着的第一个条目的附加日志请求时的一致性检查,因为这个条目需要前一日志条目的索引值和任期号 。为了支持集群成员更新(第 6 节),快照中也将最后的一次配置作为最后一个条目存下来 。一旦服务器完成一次快照,他就可以删除最后索引位置之前的所有日志和快照了 。
尽管通常服务器都是独立地创建快照,但是领导人必须偶尔的发送快照给一些落后的跟随者 。这通常发生在当领导人已经丢弃了下一条需要发送给跟随者的日志条目的时候 。幸运的是这种情况不是常规操作:一个与领导人保持同步的跟随者通常都会有这个条目 。然而一个运行非常缓慢的跟随者或者新加入集群的服务器(第 6 节)将不会有这个条目 。这时让这个跟随者更新到最新的状态的方式就是通过网络把快照发送给他们 。


推荐阅读