使用 Multi-Paxos 协议的日志同步与恢复

来源:互联网 发布:淘宝闲鱼拍卖可信吗 编辑:程序博客网 时间:2024/06/06 08:09

原文 https://zhuanlan.zhihu.com/p/20417442?columnSlug=likai

在 Basic-Paxos 协议中,所有成员的身份都是平等的,任何成员都可以提出日志持久化的提案,并且尝试在成员组中进行持久化。

而在实际的工程应用中,往往需要一个成员在一段时间内保持唯一 Leader 的身份,来服务对数据的增删改操作,产生 redolog,并尝试在成员组中进行持久化。本文讨论利用 Paxos 协议选举唯一的 leader,以及使用 leader 将 redolog 在成员组中进行持久化和恢复的方法。

Basic-Paxos 协议的执行流程
针对每条 redolog 都至少存在三次网络交互的延迟。
1、产生 LogID
由于 Basic-Paxos 有多个 Proposer,没有单一 Server 维护 logID,而是需要进行分布式协商,为不同的 redolog 分配全局唯一且有序的 logID。

2、Prepare 阶段
上一阶段分布式协商 logID 并不能保证多个 server 分配得到的 logID 是唯一的,即会出现若干条不同的 redolog 在同一个 Paxos Instance 中投票的情况。需要执行 prepare,以决定出这个 Paxos Instance 内的要进行投票的 redolog (提案)。

3、Accept 阶段
对 Prepare 阶段决定出的提案进行投票,得到多数派确认后表示 redolog 同步成功。

根据 Paxos 协议的约束,acceptor 应答 prepare 消息和 accept 消息前都要持久化本地 redolog。因此最终可以得到使用 Basic-Paxos 进行 redolog 同步的延迟包括了 3 次网络交互加 2 次写本地磁盘。

Multi-Paxos 协议概述
利用 Paxos 协议选举唯一的 leader,在 leader 有效期内所有的提案都由 leader 发起。对于 redolog 的同步过程,可以简化掉 logID 生成阶段和 prepare 阶段。由唯一的 leader 产生 logID,直接执行 accept,得到多数派确认即表示 redolog 同步成功。

leader 的产生
需要明确的是 Multi-Paxos 协议并不假设全局必须只能有唯一的 leader 来生成日志,它允许有多个“自认为是 leader 的 server”并发生成日志,这样的场景退化为 Basic-Paxos。

Multi-Paxos 可以简单理解为:经过一轮的 Basic-Paxos,成功得到多数派 accept 的 proposer 即成为 leader(这个过程称为 leader Elect),之后通过 lease 机制,保持这个 leader 的身份,使得其他 proposer 不再发起提案,这样就进入了一个 leader 任期。leader 对后续日志进行投票时,就不需要询问 logID,也不必执行 prepare 阶段,直接执行 accept 阶段即可。
我们将 leader Elect 过程中的 prepare 操作,视为对 leader 任期内将要写的所有日志的一次性 prepare 操作,在 leader 任期内投票的所有日志将携带有相同的 proposal_id。为了遵守 Basic-Paxos 协议约束,在 leader Elect 的 prepare 阶段,acceptor 应答 prepare 成功的消息之前要先将这次 prepare 请求所携带的 proposal_id 持久化到本地。

Confirm 日志的优化
在 Paxos 协议中,对于决议的读取也是需要执行一轮 Paxos 过程的,在实际工程做数据恢复时,对每条日志都执行一轮 Paxos 的代价过大。因此引入一种 commit 的机制,leader 持久化一条日志,得到多数派的 accept 后,就再写一条针对这条日志的 confirm 日志。在回放日志时,如果一条日志有对应的 commit 日志,就可以直接读取本地内容,而不需要执行一轮 Paxos。出于性能的考虑,confirm 日志往往是延迟的成批写出去,因此会出现部分日志已经被多数派接收,但是没有对应 commit 日志的情况。对于这些日志,需要在恢复过程中进行重确认。

在实际的工程实践中,可以使用基于 logID 的滑动窗口机制来限制 confirm 日志与对应的原始日志的距离,以简化日志回放与查询逻辑。

新任 leader 对日志的重确认
在恢复过程中,有 confirm 日志的原始日志,可以直接回放,没有对应 confirm 日志的原始日志,则需要执行一轮 Paxos,这个过程被称为重确认。

此外日志中的“空洞”,也需要进行重确认。因为当前 leader 在上一任 leader 的任期可能错过了一些日志的同步,而这些日志在其他机器上形成了多数派。由于 logID 连续递增,被错过的日志就成了 logID 连续递增序列中的“空洞”,需要重确认来补全。

新任 leader 在开始执行重确认前,需要先知道重确认的结束位置,因为 leader 本地相对于集群内多数派可能已经落后很多日志,需要向集群内其他 server 发送请求,查询每个 server 本地的最大 logID,并从多数派的应答中选择最大的 logID 作为重确认的结束为止。也即开始提供服务后写日志的起始 logID。

对于每条日志的重确认,需要执行一轮完成的 Paxos 过程,不管日志是否曾经形成多数派备份,都重新尝试持久化的原则,我们称之为“最大 commit 原则”。之所以在遵守该原则,是因为我们无法区分出来未形成多数派备份的日志。

重确认日志时,要使用当前 leader 的 proposal_id 作为 Paxos 协议中的 proposal_id 来对日志执行 Paxos 过程。因此在回放日志时,对于 logID 相同的多条日志,要以 proposal_id 最大的为准。

“幽灵复现”日志的处理
使用Paxos协议处理日志的备份与恢复,可以保证确认形成多数派的日志不丢失,但是无法避免一种被称为“幽灵复现”的现象

  1. 第一轮中A被选为Leader,写下了1-10号日志,其中1-5号日志形成了多数派,并且已给客户端应答,而对于6-10号日志,客户端超时未能得到应答。
  2. 第二轮,A宕机,B被选为Leader,由于B和C的最大的logID都是5,因此B不会去重确认6-10号日志,而是从6开始写新的日志,此时如果客户端来查询的话,是查询不到6-10号日志内容的,此后第二轮又写入了6-20号日志,但是只有6号和20号日志在多数派上持久化成功。
  3. 第三轮,A又被选为Leader,从多数派中可以得到最大logID为20,因此要将7-20号日志执行重确认,其中就包括了A上的7-10号日志,之后客户端再来查询的话,会发现上次查询不到的7-10号日志又像幽灵一样重新出现了。

为了处理“幽灵复现”问题,我们在每条日志的内容中保存一个generateID,leader在生成这条日志时以当前的leader ProposalID作为generateID。按logID顺序回放日志时,因为leader在开始服务之前一定会写一条StartWorking日志,所以如果出现generateID相对前一条日志变小的情况,说明这是一条“幽灵复现”日志(它的generateID会小于StartWorking日志),要忽略掉这条日志。

1 0
原创粉丝点击