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

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

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

Basic-Paxos协议

通过前面的Basic-Paxos协议的执行流程可以看出:

  • 每条redolog都需要执行一次paxos instance, 至少存在3次网络交互(1. get maxLogID; 2. prepareRequest; 3. acceptRequest;盘).
  • 机群内的server得到的LogID可能不唯一.
  • prepare阶段会有失败而需要回退到第一步"获取logID"重新执行.
  • accept阶段对prepare阶段决定出的议案进行投票, 得到多数派确认后表示redolog同步成功, 否则需要重新产生logID.
  • 根据Paxos协议的约束, acceptor应答prepareRequest和acceptRequest前都要持久化本地redolog, 以避免重启后的行为与重启前自相矛盾.

Multi-Paxos协议概述

在Paxos集群中利用Paxos协议选举唯一的leader, 在leader有效期内所有的议案都只能由leader发起, 这里强化了协议的假设: 即leader有效期内不会有其他server提出的议案. 因此对于redolog的同步过程, 我们可以简化掉产生logID阶段和prepare阶段, 而是由唯一的leader产生logID, 然后直接执行accept, 得到多数派确认即表示redolog同步成功.

Leader选举

Multi-Paxos可以简单的理解为, 经过一轮的Basic-Paxos, 成功得到多数派accept的proposer即成为leader(这个过程称为leader Election), 之后可以通过lease机制, 保持这个leader的身份, 使得其他proposer不再发起提案, 这样就进入了一个leader任期. 在leader任期中, 由于没有了并发冲突, 这个leader在对后续的日志进行投票时, 不必每次都向多数派询问logID, 也不必执行prepareRequest阶段, 直接执行acceptRequest阶段即可.

因此在Multi-Paxos中, 我们将leader Election过程中的prepare操作, 视为对leader任期内将要写的所有日志的一次性prepare操作, 在leader任期内投票的所有日志将携带有相同的proposalID. 需要强调的是, 为了遵守Basic-Paxos协议约束, 在leader Election的prepare阶段, acceptor应答prepare成功的消息之前要先将这次prepare请求所携带的proposalID持久化到本地.

由于多个server并发执行leader Election, 可能出现两个server在相近的时间内, 先后执行leader Election都成功, 都认为自己是leader的情况. 因此, 当选leader在开始以leader身份提供服务之前, 要使用leader ProposalID写一条日志(称为StartWorking日志), 得到多数派确认后, 再开始提供服务. 这是因为根据Basic-Paxos的约束, 可以推断出: 先执行leader Election成功的leader(称为L1), 它的proposalID(称为P1)一定会小于后执行leader Election成功的leader(称为L2)的proposalID(称为P2), 而经过了两轮leader Election, 机群内多数派持久化的proposalID一定是P2, 而此时L1使用P1执行accept时, 由于P1<P2, 它将无法得到机群内多数派的accept, 因此最终机群内当选的leader将会是L2.

Confirm日志优化

在Basic-Paxos协议中, 对于决议的读取也是需要执行一轮Paxos过程, 在实际工程中做数据恢复时, 对每条日志都执行一轮Paxos的代价过大. 因此引入需要引入一种被成为confirm的机制, 即leader持久化一条日志, 得到多数派的accept后, 就再写一条针对这条日志的confirm日志, 表示这条日志已经确认形成了多数派备份, 在回放日志时, 判断如果一条日志有对应的confirm日志, 则可以直接读取本地内容, 而不需要再执行一轮Paxos. confirm日志只要写本地即可, 不需要同步到备机, 但是出于提示备机及时回放收到日志的考虑(备机收到一条日志后并不能立即回放, 需要确认这条日志已经形成多数派备份才能回放), leader也会批量的给备机同步confirm日志. 出于性能的考虑, confirm日志往往是延迟的成批写出去, 因此仍然会出现部分日志已经形成多数派备份, 但是没有对应的confirm日志的情况, 对于这些日志, 需要在恢复过程中进行重确认. 因此往往follower的数据是稍微延迟的(相对于leader).

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

新任Leader对日志的reConfirm

如上一节所述, 在恢复过程中, 拥有对应confirm日志的原始日志, 可以被直接回放. 而没有对应confirm日志的原始日志, 则需要执行一轮Paxos, 这个过程被成为重确认.

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

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

对于每条日志的重确认, 需要执行一轮完整的Paxos过程, 可能有些日志在恢复前确实未形成多数派备份, 需要通过重新执行Paxos来把这些日志重新持久化才能回放. 这种不管日志是否曾经形成多数派备份, 都重新尝试持久化的原则, 称之为"最大commit原则". 之所以要遵守"最大commit原则", 是因为我们无法区分出来未形成多数派备份的日志, 而这些日志在上一任leader任期内, 也必然是"未决"状态, 尚未应答客户端, 所以无论如何都重新持久化都是安全的.

比如A/B/C三个server, 一条日志在A/B上持久化成功, 已经形成多数派, 然后B宕机; 另一种情况, A/B/C三个server, 一条日志只在A上持久化成功, 超时未形成多数派, 然后B宕机. 上述两种情况, 最终的状态都是A上有一条日志, C上没有, 在恢复时无法区分这条日志是否曾经形成过多数派, 因此干脆按照"最大commit原则"将这条日志尝试重新在A/C上持久化后再回放.

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

"幽灵复现"日志的处理

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

Leader A B C
第一轮 A 1-10 1-5 1-5
第一轮 B 宕机 1-6,20 1-6,20
第一轮 A 1-20 1-20 1-20
  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号日志又像幽灵一样重新出现了.

对于将Paxos协议应用在数据库日志同步场景的情况, "幽灵复现"问题是不可接受.

一个简单的例子就是转账场景, 用户转账时如果返回结果超时, 那么往往会查询一下转账是否成功, 来决定是否重试一下. 如果第一次查询转账结果时, 发现未生效而重试, 而转账事务日志作为幽灵复现日志重新出现的话, 就造成了用户重复转账.

处理"幽灵复现"问题, 需要依赖新任leader在完成日志重确认, 开始写入新的Redolog之前, 写出一条被称为 StartWorking的日志, 这条日志的内容中记录了当前leader的EpochID(可以使用proposalID的值), 并且leader每写一条日志都在日志内容中携带现任leader的EpochID. 回放时, 经过了一条StartWorking日志之后, 再遇到EpochID比它小的日志, 就直接忽略掉, 比如按照上面例子画出的这张图, 7-19号日志要在回放时被忽略掉.

参考:
http://research.microsoft.com/en-us/um/people/lamport/pubs/paxos-simple.pdf
http://www.cs.cmu.edu/~pavlo/courses/fall2013/static/papers/p398-chandra.pdf
http://codemacro.com/2014/10/15/explain-poxos/
http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=403582309&idx=1&sn=80c006f4e84a8af35dc8e9654f018ace&3rd=MzA3MDU4NTYzMw==&scene=6#rd
http://oceanbase.org.cn/?p=111
http://mp.weixin.qq.com/s?__biz=MjM5MDg2NjIyMA==&mid=203607654&idx=1&sn=bfe71374fbca7ec5adf31bd3500ab95a&key=8ea74966bf01cfb6684dc066454e04bb5194d780db67f87b55480b52800238c2dfae323218ee8645f0c094e607ea7e6f&ascene=1&uin=MjA1MDk3Njk1&devicetype=webwx&version=70000001&pass_ticket=2ivcW%2FcENyzkz%2FGjIaPDdMzzf%2Bberd36%2FR3FYecikmo%3D
http://static.googleusercontent.com/media/research.google.com/zh-CN//archive/chubby-osdi06.pdf

Multi-Paxos协议日志同步应用的更多相关文章

  1. Basic-Paxos协议日志同步应用

    使用Basic-Paxos协议的日志同步与恢复 传统数据库保持服务持续可用通常采用1主N备, 既采取两种日志同步模式: Maximum Availability和Maximum Protection. ...

  2. gap lock/next-key lock浅析 Basic-Paxos协议日志同步应用

    http://www.cnblogs.com/renolei/p/4673842.html 当InnoDB在判断行锁是否冲突的时候, 除了最基本的IS/IX/S/X锁的冲突判断意外, InnoDB还将 ...

  3. gap lock/next-key lock浅析Basic-Paxos协议日志同步应用

    http://www.cnblogs.com/renolei/p/4673842.html 当InnoDB在判断行锁是否冲突的时候, 除了最基本的IS/IX/S/X锁的冲突判断意外, InnoDB还将 ...

  4. Paxos 实现日志复制同步

    Paxos 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频 ...

  5. Paxos 实现日志复制同步(Multi-Paxos)

    Paxos 实现日志复制同步 这篇文章以一种易于理解的方式来解释 Multi-Paxos 的机制. Multi-Paxos 的是为了创建日志复制 一种实现方式是用一组基础 Paxos 实例,每条记录都 ...

  6. Paxos 实现日志复制同步(Basic Paxos)

    Paxos 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频 ...

  7. paxos协议更新日志

    基于Paxos协议的数据同步与传统主备方式最大的区别在与Paxos只需任意超过半数的副本在线且相互通信正常,就可以保证服务的持续可用,且数据不丢失. Basic paxos协议更新日志 我们将数据持久 ...

  8. 从 Basic Paxos 到 Multi Paxos 到 Raft

    在朴素Paxos算法中, 各个节点经过 Prepare 和 Accept 阶段, 会达成一个值, 这个值一旦达成, 就不能被修改, 如下例子: 图示1 上面的操作几乎没有任何实用价值, 于是演变成下面 ...

  9. 使用multi-paxos实现日志同步应用

    paxos 说multi-paxos之前先简要说一下paxos paxos是在多个成员之间对某个值(提议)达成一致的一致性协议.这个值可以是任何东西.比如多个成员之间进行选主,那么这个值就是主的身份. ...

随机推荐

  1. git部署详解

    1.1 关于版本控制 1.1.1 本地版本控制 本地版本控制系统 许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别.这么做唯一的 好处就是简单,但是特别容易犯错.有 ...

  2. TensorFlow 同时调用多个预训练好的模型

    在某些任务中,我们需要针对不同的情况训练多个不同的神经网络模型,这时候,在测试阶段,我们就需要调用多个预训练好的模型分别来进行预测. 调用单个预训练好的模型请点击此处 弄明白了如何调用单个模型,其实调 ...

  3. shell语句for循环

    一:常用格式 格式一 for 变量 do 语句 done 格式二 for 变量 in 列表 do 语句 done 格式三 for ((变量=初始值; 条件判断; 变量变化)) do 语句 done 二 ...

  4. jQuery添加、移除、改变class属性

    jQuery中一般有3个关于改变元素class的函数addClass.removeClass.toggleClass addClass描述: 为每个匹配的元素添加指定的样式类名$('div').add ...

  5. npm基本使用

    常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用. 允许用户将自己编写的包或命令行程序上传到NPM服 ...

  6. BZOJ4476 JSOI2015送礼物(分数规划+单调队列)

    看到这个式子当然先二分答案.得max-min-(j-i+k)ans>=0. 显然max-min相同的情况下所选区间长度越短越好,所以max和min都应该取在边界.那么实际上我们根本不用管端点是否 ...

  7. hdu 1286 找新朋友 (欧拉函数)

    找新朋友 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  8. Codeforces Round #430 (Div. 2) Vitya and Strange Lesson

    D.Vitya and Strange Lesson(字典树) 题意: 给一个长度为\(n\)的非负整数序列,\(m\)次操作,每次先全局异或\(x\),再查询\(mex\) \(1<=n< ...

  9. HDU4185:Oil Skimming(二分图最大匹配)

    Oil Skimming Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  10. PHP正则替换preg_replace函数的使用

    <?php $str="as2223adfsf0s4df0sdfsdf"; echo preg_replace("/0/","",$s ...