0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

解决分布式系统“幽灵复现”问题的四大方案

454398 来源:机器之一 作者:阿里技术 2020-10-13 16:10 次阅读

“幽灵复现”的问题本质属于分布式系统的“第三态”问题,即在网络系统里面,对于一个请求都有三种返回结果:成功,失败,超时未知。对于超时未知,服务端对请求命令的处理结果可以是成功或者失败,但必须是两者中之一,不能出现前后不一致情况。

1、“幽灵复现”问题

我们知道,当前业界有很多分布式一致性复制协议,比如Paxos,Raft,Zab及Paxos的变种协议,被广泛用于实现高可用的数据一致性。Paxos组通常有3或5个互为冗余的节点组成,它允许在少数派节点发生停机故障的情况下,依然能继续提供服务,并且保证数据一致性。作为一种优化,协议一般会在节点之间选举出一个Leader专门负责发起Proposal,Leader的存在,避免了常态下并行提议的干扰,这对于提高Proposal处理的效率有很大提升。

但是考虑在一些极端异常,比如网络隔离,机器故障等情况下,Leader可能会经过多次切换和数据恢复,使用Paxos协议处理日志的备份与恢复时,可以保证确认形成多数派的日志不丢失,但是无法避免一种被称为“幽灵复现”的现象。考虑下面一种情况:

如上表所示,在第一轮中,A成为指定Leader,发出1-10的日志,不过后面的6-10没有形成多数派,随机宕机。随后,第二轮中,B成为指定Leader,继续发出6-20的日志(B没有看到有6-10日志的存在),这次,6以及20两条日志形成了多数派。随机再次发生切换,A回来了,从多数派拿到的最大LogId为20,因此决定补空洞,事实上,这次很大可能性是要从6开始,一直验证到20。我们逐个看下会发生什么:

针对Index 6的日志,A重新走一轮basic paxos就会发现更大proposeid形成决议的6,从而放弃本地的日志6,接受已经多数派认可的日志;

针对Index 7到Index 10,因为多数派没有形成有效落盘,因此A随机以本地日志发起提议并形成多数派;

针对Index 11到Index 19,因为均没有形成有效落盘数据,因此,以noop形成补空洞;

针对Index 20,这个最简单,接受已经多数派认可的日志;

在上面的四类情况分析中,1,3,4的问题不大。主要在场景2,相当于在第二轮并不存在的7~10,然后在第三列又重新出现了。按照Oceanbase的说法,在数据库日志同步场景的情况,这个问题是不可接受的,一个简单的例子就是转账场景,用户转账时如果返回结果超时,那么往往会查询一下转账是否成功,来决定是否重试一下。如果第一次查询转账结果时,发现未生效而重试,而转账事务日志作为幽灵复现日志重新出现的话,就造成了用户重复转账。

2、基于 Multi-Paxos 解决“幽灵复现”问题

为了处理“幽灵复现”问题,基于Multi-Paxos实现的一致性系统,可以在每条日志内容保存一个epochID,指定Proposer在生成这条日志时以当前的ProposalID作为epochID。按logID顺序回放日志时,因为leader在开始服务之前一定会写一条StartWorking日志,所以如果出现epochID相对前一条日志变小的情况,说明这是一条“幽灵复现”日志,要忽略掉这条日志(说明一下,我认这里顺序是先补空洞,然后写StartWorkingID,然后提供服务)。

以上个例子来说明,在Round 3,A作为leader启动时,需要日志回放重确认,index 1~5 的日志不用说的,epochID为1,然后进入epochID为2阶段,index 6 会确认为epochID为2的StartWorking日志,然后就是index 7~10,因为这个是epochID为1的日志,比上一条日志epochID小,会被忽略掉。而Index 11~19的日志,EpochID应该是要沿袭自己作为Leader看到的上上一轮StartWorkingID(当然,ProposeID还是要维持在3的),或者因为是noop日志,可以特殊化处理,即这部分日志不参与epochID的大小比较。然后index 20日志也会被重新确认。最后,在index 21写入StartWorking日志,并且被大多数确认后,A作为leader开始接收请求。

3、基于Raft解决“幽灵复现”问题

3.1 关于Raft日志恢复

首先,我们聊一下Raft的日志恢复,在 Raft 中,每次选举出来的Leader一定包含已经Committed的数据(抽屉原理,选举出来的Leader是多数中数据最新的,一定包含已经在多数节点上Commit的数据),新的Leader将会覆盖其他节点上不一致的数据。虽然新选举出来的Leader一定包括上一个Term的Leader已经Committed的Log Entry,但是可能也包含上一个Term的Leader未Committed的Log Entry。这部分Log Entry需要转变为Committed,相对比较麻烦,需要考虑Leader多次切换且未完成Log Recovery,需要保证最终提案是一致的,确定的,不然就会产生所谓的幽灵复现问题。

因此,Raft中增加了一个约束:对于之前Term的未Committed数据,修复到多数节点,且在新的Term下至少有一条新的Log Entry被复制或修复到多数节点之后,才能认为之前未Committed的Log Entry转为Committed。

为了将上一个Term未Committed的Log Entry转为Committed,Raft 的解决方案如下:

Raft算法要求Leader当选后立即追加一条Noop的特殊内部日志,并立即同步到其它节点,实现前面未Committed日志全部隐式提交。

从而保证了两个事情:

通过最大Commit原则保证不会丢数据,即是保证所有的已经Committed的Log Entry不会丢;

保证不会读到未Committed的数据,因为只有Noop被大多数节点同意并提交了之后(这样可以连带往期日志一起同步),服务才会对外正常工作;Noop日志本身也是一个分界线,Noop之前的Log Entry被提交,之后的Log Entry将会被丢弃。

3.2 Raft解决“幽灵复现”问题

针对第一小节的场景,Raft中是不会出现第三轮A当选leader的情况,首先对于选举,候选人对比的是最后一条日志的任期号(lastLogTerm)和日志的长度(lastLogIndex)。B、C的lastLogTerm(t2)和lastLogIndex(20)都比A的lastLogTerm(t1)和lastLogIndex(10)大,因此leader只能出现在B、C之内。假设C成为leader后,Leader运行过程中会进行副本的修复,对于A来说,就是从log index为6的位置开始,C将会把自己的index为6及以后的log entry复制给A,因此A原来的index 6-10的日志删除,并保持与C一致。最后C会向follower发送noop的log entry,如果被大多数都接收提交后,才开始正常工作,因此不会出现index 7-10能读到值的情况。

这里考虑另一个更通用的幽灵复现场景。考虑存在以下日志场景:

1)Round 1,A节点为leader,Log entry 5,6内容还没有commit,A节点发生宕机。这个时候client 是查询不到 Log entry 5,6里面的内容。

2)Round 2,B成为Leader, B中Log entry 3, 4内容复制到C中, 并且在B为主的期间内没有写入任何内容。

3)Round 3,A 恢复并且B、C发生重启,A又重新选为leader, 那么Log entry 5, 6内容又被复制到B和C中,这个时候client再查询就查询到Log entry 5, 6 里面的内容了。

Raft里面加入了新Leader 必须写入一条当前Term的Log Entry 就可以解决这个问题, 其实和MultiPaxos提到的写入一个StartWorking 日志是一样的做法, 当B成为Leader后,会写入一个Term 3的noop日志,这里解决了上面所说的两个问题:

Term 3的noop日志commit前,B的index 3,4的日志内容一定会先复制到C中,实现了最大commit原则,保证不会丢数据,已经 commit 的 log entry 不会丢。

就算A节点恢复过来, 由于A的lastLogTerm比B和C都小,也无法成了Leader, 那么A中未完成的commit只是会被drop,所以后续的读也就不会读到Log Entry 5,6里面的内容。

4、基于Zab解决“幽灵复现”问题

4.1 关于Zab的日志恢复

Zab在工作时分为原子广播和崩溃恢复两个阶段,原子广播工作过程也可以类比raft提交一次事务的过程。

崩溃恢复又可以细分为Leader选举和数据同步两个阶段。

早期的Zab协议选举出来的Leader满足下面的条件:

a) 新选举的Leader节点含有本轮次所有竞选者最大的zxid,也可以简单认为Leader拥有最新数据。该保证最大程度确保Leader具有最新数据。

b) 竞选Leader过程中进行比较的zxid,是基于每个竞选者已经commited的数据生成。

zxid是64位高32位是epoch编号,每经过一次Leader选举产生一个新的leader,新的leader会将epoch号+1,低32位是消息计数器,每接收到一条消息这个值+1,新leader选举后这个值重置为0。这样设计的好处在于老的leader挂了以后重启,它不会被选举为leader,因此此时它的zxid肯定小于当前新的leader。当老的leader作为follower接入新的leader后,新的leader会让它将所有的拥有旧的epoch号的未被commit的proposal清除。

选举出leader后,进入日志恢复阶段,会根据每个Follower节点发送过来各自的zxid,决定给每个Follower发送哪些数据,让Follower去追平数据,从而满足最大commit原则,保证已commit的数据都会复制给Follower,每个Follower追平数据后均会给Leader进行ACK,当Leader收到过半Follower的ACK后,此时Leader开始工作,整个zab协议也就可以进入原子广播阶段。

4.2 Zab解决“幽灵复现”问题

对于第 1 节的场景,根据ZAB的选举阶段的机制保证,每次选举后epoch均会+1,并作为下一轮次zxid的最高32位。所以,假设Round 1阶段,A,B,C的EpochId是1,那么接下来的在Round 2阶段,EpochId为2,所有基于这个Epoch产生的zxid一定大于A上所有的zxid。于是,在Round 3,由于B, C的zxid均大于A,所以A是不会被选为Leader的。A作为Follower加入后,其上的数据会被新Leader上的数据覆盖掉。可见,对于情况一,zab是可以避免的。

对于 3.2 节的场景,在Round 2,B选为leader后,并未产生任何事务。在Round 3选举,由于A,B,C的最新日志没变,所以A的最后一条日志zxid比B和C的大,因此A会选为leader,A将数据复制给B,C后,就会出现”幽灵复现“现象的。

为了解决“幽灵复现”问题,最新Zab协议中,每次leader选举完成后,都会保存一个本地文件,用来记录当前EpochId(记为CurrentEpoch),在选举时,会先读取CurrentEpoch并加入到选票中,发送给其他候选人,候选人如果发现CurrentEpoch比自己的小,就会忽略此选票,如果发现CurrentEpoch比自己的大,就会选择此选票,如果相等则比较zxid。因此,对于此问题,Round 1中,A,B,C的CurrentEpoch为2;Round 2,A的CurrentEpoch为2,B,C的CurrentEpoch为3;Round 3,由于B,C的CurrentEpoch比A的大,所以A无法成为leader。

5、 进一步探讨

在阿里云的女娲一致性系统里面,做法也是类似于Raft与Zab,确保能够制造幽灵复现的角色无法在新的一轮选举为leader,从而避免幽灵日志再次出现。从服务端来看“幽灵复现”问题,就是在failover情况下,新的leader不清楚当前的committed index,也就是分不清log entry是committed状态还是未committed状态,所以需要通过一定的日志恢复手段,保证已经提交的日志不会被丢掉(最大 commit 原则),并且通过一个分界线(如MultiPaxos的StartWorking,Raft的noop,Zab的CurrentEpoch)来决定日志将会被commit还是被drop,从而避免模糊不一的状态。“幽灵复现”的问题本质属于分布式系统的“第三态”问题,即在网络系统里面, 对于一个请求都有三种返回结果:成功,失败,超时未知。对于超时未知,服务端对请求命令的处理结果可以是成功或者失败,但必须是两者中之一,不能出现前后不一致情况。在客户端中,请求收到超时,那么客户端是不知道当前底层是处于什么状况的,成功或失败都不清楚,所以一般客户端的做法是重试,那么底层apply的业务逻辑需要保证幂等性,不然重试会导致数据不一致。
编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 网络系统
    +关注

    关注

    0

    文章

    85

    浏览量

    25043
  • 分布式系统
    +关注

    关注

    0

    文章

    146

    浏览量

    19234
  • 阿里云
    +关注

    关注

    3

    文章

    956

    浏览量

    43047
收藏 人收藏

    评论

    相关推荐

    基于ptp的分布式系统设计

    在现代分布式系统中,精确的时间同步对于确保数据一致性、系统稳定性和性能至关重要。PTP(Precision Time Protocol)是一种网络协议,用于在分布式
    的头像 发表于 12-29 10:09 76次阅读

    分布式光伏监控系统在能源领域中的重要性

    在当今能源领域,分布式光伏发电作为一种可持续的能源解决方案正日益普及。而分布式光伏监控系统在其中扮演着至关重要的角色,为分布式光伏发电的高效
    的头像 发表于 12-09 14:39 223次阅读
    <b class='flag-5'>分布式</b>光伏监控<b class='flag-5'>系统</b>在能源领域中的重要性

    分布式光纤测温解决方案

    分布式光纤测温解决方案
    的头像 发表于 11-12 01:02 153次阅读
    <b class='flag-5'>分布式</b>光纤测温解决<b class='flag-5'>方案</b>

    基于分布式存储系统医疗影像数据存储解决方案

    基于分布式存储系统医疗影像数据存储解决方案
    的头像 发表于 09-14 09:53 316次阅读
    基于<b class='flag-5'>分布式</b>存储<b class='flag-5'>系统</b>医疗影像数据存储解决<b class='flag-5'>方案</b>

    黑龙江电力高性能WDS分布式存储系统解决方案

    黑龙江电力高性能WDS分布式存储系统解决方案
    的头像 发表于 07-01 09:54 378次阅读
    黑龙江电力高性能WDS<b class='flag-5'>分布式</b>存储<b class='flag-5'>系统</b>解决<b class='flag-5'>方案</b>

    分布式SCADA系统的特点的组成

    在工业自动化和能源管理领域,SCADA(Supervisory Control And Data Acquisition)系统扮演着至关重要的角色。其中,分布式SCADA系统凭借其独特的结构和功能
    的头像 发表于 06-07 14:43 550次阅读

    分布式光伏监控系统解决方案

    分布式光伏发电系统的发电量,提高分布式光伏发电系统的利用率。发展分布式光伏发电对优化能源结构、实现“双碳目标”、推动节能减排、实现经济可持续
    的头像 发表于 04-22 15:56 990次阅读
    <b class='flag-5'>分布式</b>光伏监控<b class='flag-5'>系统</b>解决<b class='flag-5'>方案</b>

    HarmonyOS实战案例:【分布式账本】

    Demo基于Open Harmony系统使用ETS语言进行编写,本Demo主要通过设备认证、分布式拉起、分布式数据管理等功能来实现。
    的头像 发表于 04-12 16:40 1333次阅读
    HarmonyOS实战案例:【<b class='flag-5'>分布式</b>账本】

    分布式光伏电力监控系统解决方案

    安科瑞薛瑶瑶18701709087 分布式光伏现状 自发自用、余电上网模式 完全自发自用(防逆流)模式 全额上网模式 0.4kV并网系统   此图为车间新建屋顶分布式光伏发电项目,建设装机容量为
    的头像 发表于 03-18 11:18 800次阅读
    <b class='flag-5'>分布式</b>光伏电力监控<b class='flag-5'>系统</b>解决<b class='flag-5'>方案</b>

    分布式存储与计算:大数据时代的解决方案

    分布式存储和计算技术应运而生,并迅速成为处理大数据的首选方案。本文将深入探讨分布式存储和计算的概念、优势及其在各个领域的应用情况。 1.分布式存储和计算的概念与优势
    的头像 发表于 03-07 14:42 775次阅读

    分布式大屏控制系统对网络环境的要求

    分布式大屏控制系统对网络环境的要求较高,主要是因为该系统需要实时传输大量的视频信号数据,以保证多个显示屏幕的同步显示。以下是几个关键的网络环境要求: 高带宽:分布式大屏控制
    的头像 发表于 01-29 14:52 580次阅读

    分布式大屏控制系统的工作原理

    分布式大屏控制系统是一种基于分布式计算、云计算和大数据技术的控制系统,具有高效、稳定、灵活的特点。该系统通过将各个子
    的头像 发表于 01-29 14:24 762次阅读

    分布式智慧终端:挑战与解决方案

    分布式智慧终端在应用中面临多种挑战,以下是其中一些关键的挑战以及可能的解决方案: 数据一致性挑战 :在分布式系统中,数据的一致性是一个关键问题。由于数据
    的头像 发表于 01-24 14:50 448次阅读

    分布式光伏电力监控解决方案

    分布式光伏电力监控解决方案
    的头像 发表于 01-14 08:07 591次阅读
    <b class='flag-5'>分布式</b>光伏电力监控解决<b class='flag-5'>方案</b>

    什么是分布式架构?

    分布式架构是指将一个系统或应用拆分成多个独立的节点,这些节点通过网络连接进行通信和协作,以实现共同完成任务的一种架构模式。这种架构模式旨在提高系统的可扩展性、可靠性和性能表现。 一、分布式
    的头像 发表于 01-12 15:04 1245次阅读
    什么是<b class='flag-5'>分布式</b>架构?