使用multi-paxos实现日志同步应用
paxos
说multi-paxos之前先简要说一下paxos
paxos是在多个成员之间对某个值(提议)达成一致的一致性协议。这个值可以是任何东西。比如多个成员之间进行选主,那么这个值就是主的身份。在把multi-paxos协议应用在日志同步中时,这个值就是一条日志。网上讲paxos的文章已经很多了,这里简要说明一下。
paxos分为prepare和accept两个阶段。协议中有两个主要的角色,proposer和acceptor。
value被majority accept之前,每个acceptor可以accept多个不同的值。但是,一旦一个value被majority accept(即value达成一致),那么这个value就不会变了。因为prepare阶段会将该value给找出来,随后accept阶段会使用这个value,后续的所有的提案都会选择这个value。
需要注意的是,每个阶段都是收到majority的响应后即开始处理。并且由于机器会宕机,acceptor需要对acceptedProposalID, acceptedValue和minProposal进行持久化。
从流程中可以看出prepare有两个作用:
- 大的proposal id会block未完成的小的proposal id达成一致的过程,所以为了减少无效的prepare请求,每次都选择比自己以往见过的proposal id更大的id。
- 一旦某个value达成一致,那么后续的prepare都会找到这个value作为accept阶段的值
可以看出,一次paxos达成一致至少需要两次网络交互。
multi-paxos
paxos是对一个值达成一致,multi-paxos是运行多个paxos instance来对多个值达成一致,每个paxos instance对一个值达成一致。在一个支持多写并且强一致性的系统中,每个节点都可以接收客户端的写请求,生成redo日志然后开始一个paxos instance的prepare和accept过程。这里的问题是每条redo日志到底对应哪个paxos instance。
在日志同步应用中,用log id来区分不同的paxos instance。每条日志都由一个id唯一标示,这个log id标识一个paxos instance,这个paxos instance达成一致,即对应的日志内容达成一致,即majority的成员accept了这个日志内容。在一个由N个机器(每个机器既承担proposer也承担acceptor角色)组成的集群(通常叫做paxos group)中,每个proposer都可以产生redo日志并且进行paxos instance,那么每条redo日志到底使用哪个log id? 显然,每个proposer都会选择自己知道的还没有达成一致的最小的log id来作为这次日志的log id,然后运行paxos协议,显然,多个proposer可能会选择同一个log id(最典型的场景就是空集群启动的情况下),最终,只有一个proposer能够成功,那么其他的proposer就需要选择更大的未达成一致的log id来运行paxos。显然,这种冲突是非常严重的,会有很多的proposer成功不了进而选择更大的log id来运行paxos。
在真实的系统中,比如chubby, spanner,都会在paxos group中选择一个成员作为leader,只有leader能够propose日志,这样,prepare阶段就不会存在冲突,相当于对整个log文件做了一次prepare,后面这些日志都可以选用同一个proposal id。这样的话,每条日志只需要一次网络交互就能达成一致。回顾一下文章开头提到paxos中需要每个成员需要记录3个值,minProposal,acceptedProposal,acceptedValue,其中后面两个值可以直接记录在log中,而第一个值minProposal可以单独存在一个文件中。由于这里后面的日志都可以选用同一个proposal id,显然,在大部分时间内,minProposal都不需要改变。这正是multi-paxos的精髓
选主
对于paxos来说,主的身份无所谓,主不需要像raft那样拥有最全的已经commit的日志。所以选主算法无所谓,比如大家都给机器ip最大的机器投票,或者给日志最多的投票,或者干脆直接运行一次paxos,值的内容就是主的身份。显然,由于对新主的身份无限制,那么,新主很有可能没有某些已经达成一致的日志,这个时候,就需要将这些已达成一致的日志拉过来,另外,新主也有可能没有某些还未达成一致的日志。如下图所示:
图中,恢复之前,log id等于3的日志C已经在多数派上达成了一致,但是在新主上没有。比如log id等于4的日志D在多数派上没有达成一致,在新主上也没有。
恢复
新主向所有成员发送查询最大log id的请求,收到majority的响应后,选择最大的log id作为日志恢复的结束点。图中,如果收到的majority不包括2号成员,那么log id=6为恢复结束点。如果收到的majority包括2号成员,那么log id=7为恢复结束点。这里取majority的意义在于恢复结束点包含任何的majority达成一致的日志。拿到log id后,从头开始扫描日志,对于每条日志都运行paxos协议确认一次:如果日志之前已经达成一致了,比如日志A,B,C,E,F,那么再次运行paxos的prepare阶段会把日志内容找出来作为accept阶段的值,不影响结果。如果日志之前并没有达成一致,比如日志D,那么当返回的majority中包含3号成员时,D会被选出来当作accept阶段的值,当返回的majority中不包含3号成员时,那么D实际上不会被选出,这时主可以选择一个dummy日志作为accept阶段的值。
恢复优化
可以看出,如果日志非常多,每次重启后都要对每条日志做一次paxos,那么恢复时间可想而知。在上面的例子中,A,B,E已经达成一致,做了无用功。paxos协议中,只有主即proposer知道哪些日志达成了一致,acceptor不知道,那么很容易想到的一个优化就是proposer将已经达成一致的日志id告诉其他acceptor,acceptor写一条确认日志到日志文件中。后续重启的时候,扫描本地日志只要发现对应的确认日志就知道这条日志已经达成多数派,不需要重新使用paxos进行确认了。这种做法有一个问题,考虑如下场景:
旧主成功的给自己和2号成员发送了确认日志,但是没有给3号成员发送成功旧挂了,然后2号成员被选为新主,那么新主不会对log id=3的日志重新运行paxos,因为本机已经存在确认日志。这样的话,3号成员就回放log id=3的日志到上层了。解决这个问题的做法就是followers需要主动的向主询问日志到底有没有达成一致,如果有,则自己补充确认日志。
回放
宕机重启后,对未达成一致的日志重新运行paxos时,如log id=4的日志,如果返回的majority中不包含3号成员,那么日志D不会被找出来,这样就需要将3号成员的log id=4日志置未一条无操作的日志记作NOP日志,D最终也就不会形成多数派。由于multi-paxos允许日志乱序接收,并且日志的长度几乎都不一样,所以在磁盘上log id是乱序的,所以从物理上说,每个成员的日志不是一模一样的。那么要把log id=4的日志覆盖写成NOP日志也就比较麻烦,需要为每条日志维护索引。实现上可以不覆盖写,直接append一条log id=4的NOP日志到日志文件,这样没有问题,因为回放的时候只会回放能找到确认日志的日志到上层应用中。
成员变更
multi-paxos处理成员变更比较简单,规定第i条日志参与paxos同步的时候,其成员组是第i-k条日志包含的成员组(每条日志里面都包含成员组)。
multi-paxos协议之外
multi-paxos只是保证大家对日志达成一致。但是具体multi-paxos运用到真实的系统中时,从应用层面上看,可能会出现一些诡异的问题。考虑如下场景:
如图,1号主写了A,B,C,D,其中B,C,D没有形成多数派,然后A宕机了,2号被选为了主,客户端过来读不到B,C,D,然后B没写任何东西,就挂了,这个时候,A起来后重新被选为主,对B,C,D重新运行paxos,把B,C,D达成了一致,这个时候客户端再次过来读,又能读到B,C,D了。对于multi-paxos本身来说,并没有什么不对的地方,但是上层应用的语义出现了问题:曾经读不到的东西,什么都没做,又能读到了。
解决这个问题的方法是通过主提供服务之前必须成功写入一条start working日志来解决。如下图:
如图,每个成员成为主提供服务之前都要首先写一条start working日志,只有达成多数派才能提供服务。1号在重新成为主之后,通过对log id=2的日志运行paxos,将2号start日志恢复了出来,然后对C和D运行paxos恢复出来后,后续回放的时候,如果发现后面日志中带有的timestamp(其实时leader上任时间)比start working带有的timestamp更小,那么就不回放到上层。随后客户端来读仍然读不到B,C,D,前后保持一致。
使用multi-paxos实现日志同步应用的更多相关文章
- Paxos 实现日志复制同步
Paxos 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频 ...
- Paxos 实现日志复制同步(Multi-Paxos)
Paxos 实现日志复制同步 这篇文章以一种易于理解的方式来解释 Multi-Paxos 的机制. Multi-Paxos 的是为了创建日志复制 一种实现方式是用一组基础 Paxos 实例,每条记录都 ...
- Paxos 实现日志复制同步(Basic Paxos)
Paxos 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频 ...
- 从 Basic Paxos 到 Multi Paxos 到 Raft
在朴素Paxos算法中, 各个节点经过 Prepare 和 Accept 阶段, 会达成一个值, 这个值一旦达成, 就不能被修改, 如下例子: 图示1 上面的操作几乎没有任何实用价值, 于是演变成下面 ...
- Multi-Paxos协议日志同步应用
使用Multi-Paxos协议的日志同步与恢复 基于Basic-Paxos协议的日志同步方案, 所有成员的身份都是平等的, 任何成员都可以提出日志持久化的提案, 并且尝试在成员组中进行持久化. 而在实 ...
- Basic-Paxos协议日志同步应用
使用Basic-Paxos协议的日志同步与恢复 传统数据库保持服务持续可用通常采用1主N备, 既采取两种日志同步模式: Maximum Availability和Maximum Protection. ...
- kafka日志同步至elasticsearch和kibana展示
kafka日志同步至elasticsearch和kibana展示 一 kafka consumer准备 前面的章节进行了分布式job的自动计算的概念讲解以及实践.上次分布式日志说过日志写进kafka, ...
- Multi Paxos
Multi Paxos [2] 通过basic paxos 以上步骤分布式系统已经能确定一个值,“只确定一个值有什么用?这可解决不了我面临的问题.” 你心中可能有这样的疑问. 原simple paxo ...
- cdnbest如何查看站点操作日志(同步日志)
1. 在区域列表点同步日志 2. 点击进入后,可以查看对哪个站点进行了操作,操作时间,ip,id都有记录 3. 想知道详细操作了什么内容把鼠标指向操作类型,就会弹出操作的信息
随机推荐
- 微软消息分析器(Microsoft Message Analyzer )更新至1.2版-2015-1-20
就在刚才,收到了微软Connect的邮件推送,大名鼎鼎的微软消息分析器更新至1.2版,并且有公众下载链接,大家可以在这里进行下载. 这里简单摘录一下博客里面提到的新版所增加的功能与功能的改进方面. G ...
- 1Z0-053 争议题目解析24
1Z0-053 争议题目解析24 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 24.Which of the following information will be gath ...
- 【LeetCode】Verify Preorder Serialization of a Binary Tree(331)
1. Description One way to serialize a binary tree is to use pre-order traversal. When we encounter a ...
- 去哪儿搜索引擎QSearch设计与实现
本次演讲主要介绍的是QSearch的具体设计和应用场景,并分别解答以下几个问题:QSearch与开源垂直软件Lucene的区别:具体业务的实现技巧.以及QSearch的具体设计:如何通过Partial ...
- Date, TimeZone, MongoDB, java中date的时区问题
打印new Date(),Fri Aug 12 13:37:51 CST 2016. 显示Asia/Shanghai的时区,但是date toString 的时区简写却是CST.更坑爹的是,Googl ...
- [Java IO]01_File类和RandomAccessFile类
File类 File类是java.io包中唯一对文件本身进行操作的类.它可以进行创建.删除文件等操作. File类常用操作 (1)创建文件 可以使用 createNewFille() 创建一个新文 ...
- CSS-float详解,深入理解clear:both[转+部分原创]
首先要知道,div是块级元素,在页面中独占一行,自上而下排列,也就是传说中的流. 可以看出,即使div1的宽度很小,页面中一行可以容下div1和div2,div2也不会排在div1后边,因为div元素 ...
- pushState、replaceState、onpopstate 实现Ajax页面的前进后退刷新
使用Ajax可以异步获取数据,可以更高效地渲染页面. 但也存在这一些问题: 再刷新页面,页面就会变成初始的状态 浏览器的前进后退功能无效 对搜索引擎的爬虫抓取不友好 1. 早前会使用浏览器的 hash ...
- 10.Configure One-to-Many(配置一对多关系)【Code-First系列】
现在,我们将学习怎么配置一对多的关系. Visit Entity Relationship section to understand how EF manages one-to-one, one-t ...
- node-inspector调试工具应用
一.起因 想调试某些开源的nodejs项目,然后就选择了node-inspector插件. 他的优点: 1.可以借用chrome或firefox浏览器进行调试,与前端调试融合. 2.配置简单 二.必备 ...