分布式协议算法——paxos,raft和zab

1. paxos算法的背景

Paxos算法是莱斯利·兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一,其解决的问题就是在分布式系统中如何就某个值(决议)达成一致。Paxos算法的前提假设是不存在拜占庭将军问题,即:信道是安全的(信道可靠),发出的信号不会被篡改。

1.1 Paxos算法

在Paxos算法中,有三种角色:

  • Proposer:提案Proposal提出者
  • Acceptor:决策者,可以批准议案
  • Learner:最终决策的学习者

Paxos算法安全性前提如下:

  • 只有被提出的value才能被选定。
  • 只有一个value被选定,并且如果某个进程认为某个value被选定了,那么这个value必须是真的被选定的那个。

Paxos算法类似于两阶段提提交,其算法执行过程分为两个阶段。具体如下

  • prepare阶段
    • proposer提出一个编号为N的proposal,发送给半数以上的acceptor。
    • acceptor收到编号为N的prepare请求后:
      • 如果小于它已经相应过的请求,则拒绝回复或者回复error;
      • 如果N大于该Acceptor已经响应过的所有Prepare请求的编号,那么它就会将它已经接受过(已经经过第二阶段accept的提案)的编号最大的提案(如果有的话,如果还没有的accept提案的话返回{pok,null,null})作为响应反馈给Proposer,同时该Acceptor承诺不再接受任何编号小于N的提案。(分为两种情况:如果acceptor已经接受过提案,返回接受提案的最大value;如果还没有接受过提案,就返回{pok,null,null})
  • accept阶段
    • 如果proposer收到半数以上的acceptor回复的编号为N的提案的prepare响应,那么会发送一个针对[N,V]提案的Accept请求给半数以上的Acceptor。注意:V就是收到的响应中编号最大的提案的value。如果响应中不包含任何提案,那么V就由Proposer自己决定,可以是任意值。
    • 如果Acceptor收到一个针对编号为N的提案的Accept请求,只要该Acceptor没有对编号大于N的Prepare请求做出过响应,它就接受该提案。如果N小于Acceptor以及响应的prepare请求,则拒绝,不回应或回复error(当proposer没有收到过半的回应,那么他会重新进入第一阶段,递增提案号,重新提出prepare请求)。

图来自:Zookeeper系列(3)--Paxos算法的原理及过程透彻理解_冷面寒枪biu的博客-CSDN博客_zookeeper算法     从上一篇我们了解了2PC和3PC之后,我们可以发现,无论是二阶段提交还是三阶段提交都无法彻底解决分布式的一致性问题以及无法解决太过保守及容错性不好。Google Chubby的作者Mike Burrows说过,世上只有一种一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整版。Paxos算法是公认的晦涩,很难可能能将清楚,但是工程上也很难实现,所以有很多Paxos算...https://blog.csdn.net/u013679744/article/details/79222103
过半的acceptor都接受提案后,learner会自动感知到,并开始学习提案。(同一个进程可以同时扮演多个角色)

1.2 Learner的学习过程

learner学习过程包含两种场景:

  • Learner所在节点参与了提案选举,Learner需要知道其接受(accept)的提案值是否被选中(chosen)。
  • Learner所在节点已落后于其他节点,Learner需要选择合适的策略快速完成追赶,并重新参与到提案选举当中。

1、选中通知

正常情况下,所有节点处于online状态,共同参与paxos选举。为了避免instance id冲突,paxos建议只由主节点的proposer发起提案,保证接受提案和习得提案编号一致。此时,Learn习得的提案值实际上就是本节点Accept的数据,因此learner只更新内存状态即可,无需再次落盘(acceptor已落盘)。最后,如果存在follower节点,数据同步到follower(follower节点不参与paxos算法,相当于某个paxos节点的同步备)。

2、提案值追赶

一旦节点处于落后状态,它无法再参与到paxos提案选举中来。这时需要由learner发起主动学习完成追赶。Paxos启动时,启动learner定时器,定时发送learn请求到各个节点,发送请求携带本节点的Instance ID、Node ID信息。各节点收到该请求后,回复数据自主完成学习过程。

1.3 paxos常见问题:

问:learner如何知道某个提案是否被选中呢?
答:“3.1 选中通知”是通知各个learner值是否已被选中的一种常规方式。

问:如果某个值被选中后,提案发起节点异常,选中消息未发出会如何?
答:重新发起选举,新的被选中的提案编号不同,但提案值保持不变。

问:“3.1 选中通知”中,只更新了内存状态,在持久化的数据中,如何区分一个值的状态是accept还是chosen呢?
答: 如果当前的instance id为N,在N-1之前的所有提案值都是chosen的。当instance id为N的提案值可能是chosen状态、也可能是accept状态。

问:为何非chosen状态的数据也需要落盘
答:参见P2C的不变性,即Prepare和Accept阶段做过的承诺、接受过的值即便节点重启等异常情况下也需要保持不变。

为什么要有两段提交
一方面,第一次预提交后可能被告知已经有观点了,此时他不应该提出自己的观点,而应该尽快收敛,支持最新的观点。另一方面,进行预加锁。

怎么保证Proposal编号唯一
假设有K台Server运行paxos算法,那么他们初始编号为0…k-1。以后编号每次增加k,从而保证全局唯一递增。

正式提案被半数以上Acceptor接受后,就可以确定最终被接受的提案就是该观点
两个半数以上的集合的一定存在交集。

Paxos算法有活锁问题存在。

2. raft算法

Paxos 算法虽然很有效,但复杂的原理使它实现起来非常困难,截止目前,实现 Paxos 算法的开源软件很少,比较出名的有 Chubby、LibPaxos。此外,Zookeeper 采用的 ZAB(Zookeeper Atomic Broadcast)协议也是基于 Paxos 算法实现的,不过 ZAB 对 Paxos 进行了很多改进与优化,两者的设计目标也存在差异——ZAB 协议主要用于构建一个高可用的分布式数据主备系统,而 Paxos 算法则是用于构建一个分布式的一致性状态机系统。

Raft是一个共识算法(consensus algorithm),所谓共识,就是多个节点对某个事情达成一致的看法,即使部分节点故障、网络延时、网络分割的情况下。共识算法的实现一般是基于复制状态机(Replicated state machines),何为复制状态机:简单来说:相同的初识状态 + 相同的输入 = 相同的结束状态。

2.1 raft算法描述

一个Raft集群包含若干个节点,这些节点分为三种状态:Leader、 Follower和Candidate。正常情况下,集群中的节点只存在 Leader 与 Follower 两种状态。

  • leader:负责日志的同步管理,处理来自客户端的请求,与Follower保持heartBeat的联系;
  • follower:响应 Leader 的日志同步请求,响应Candidate的邀票请求,以及把客户端请求到Follower的事务转发(重定向)给Leader;
  • candidate:负责选举投票,集群刚启动或者Leader宕机时,状态为Follower的节点将转为Candidate并发起选举,选举胜出(获得超过半数节点的投票)后,从Candidate转为Leader状态。

还有一个关键概念:term(任期)。以选举(election)开始,每一次选举term都会自增,充当了逻辑时钟的作用

为简化逻辑和实现,Raft 将一致性问题分解成了三个相对独立的子问题:

  • 选举:当 Leader 宕机或者集群初创时,一个新的 Leader 需要被选举出来;
  • 日志复制:Leader 接收来自客户端的请求并将其以日志条目的形式复制到集群中的其它节点,并且强制要求其它节点的日志和自己保持一致;
  • 安全性:如果有任何的服务器节点已经应用了一个确定的日志条目到它的状态机中,那么其它服务器节点不能在同一个日志索引位置应用一个不同的指令。

2.1.1 选举过程

如果follower在election timeout内没有收到来自leader的心跳,则会主动发起选举。

第一阶段:所有节点都是 Follower。

        Raft 集群刚启动或 Leader 宕机时,所有节点的状态都是 Follower,初始 Term(任期)为 0。同时启动选举定时器,每个节点的选举定时器超时时间都在 100~500 毫秒之间且并不一致。

第二阶段:Follower 转为 Candidate 并发起投票。

        没有leader后,followers状态自动转为candidate,并向集群中所有节点发送投票请求并且重置选举定时器。投票过程有:

  • 增加节点本地的 current term ,切换到candidate状态;
  • 投自己一票,并行给其他节点发送 RequestVote RPCs;
  • 等待其他节点的回复,可能出现三种结果:
    • 收到majority的投票(含自己的一票),则赢得选举,成为leader;
    • 被告知别人已当选,那么自行切换到follower;
    • 一段时间内没有收到majority投票,则保持candidate状态,重新发出选举。

第三阶段:投票策略 

投票的约束条件有:

  • 在一个term内,一个节点只允许发出一次投票;
  • 候选人知道的信息不能比自己的少(这一部分,后面介绍log replication和safety的时候会详细介绍);
  • first-come-first-served 先来先得;
  • 如果参加选举的节点是偶数个,raft通过randomized election timeouts来尽量避免平票情况,也要求节点的数目都是奇数个,尽量保证majority的出现。

2.1.2 日志复制 log Replication

当leader选举成功后,客户端所有的请求都交给了leader,leader调度请求的顺序性和followers的状态一致性。在集群中,所有的节点都可能变为leader,为了保证后续leader节点变化后依然能够使集群对外保持一致,需要通过Log Replication机制来解决如下两个问题:

  • Follower与Leader节点相同的顺序依次执行每个成功提案;
  • 每个成功提交的提案必须有足够多的成功副本,来保证后续的访问一致

第一阶段:客户端请求提交到 Leader。

        Leader在收到client请求提案后,会将它作为日志条目(Entry)写入本地log中。需要注意的是,此时该 Entry 的状态是未提交(Uncommitted),Leader 并不会更新本地数据,因此它是不可读的。

第二阶段:Leader 将 Entry 发送到其它 Follower

        Leader与Floolwers 之间保持着心跳联系,随心跳 Leader 将追加的条目(AppendEntries)并行地发送给其它的 Follower,并让它们复制这条日志条目,这一过程称为复制(Replicate)。

  • 为什么 Leader 向Follower 发送的是 AppendEntries?

因为 Leader与Follower 的心跳是周期性的,而一个周期间 Leader 可能接收到多条客户端的请求,因此,随心跳向 Followers 发送的大概率是多个 Entry,即 AppendEntries。

  • Leader向Followers发送AppendEntries外还包含什么信息?

Leader 还会把新的日志条目紧接着之前条目的索引位置(prevLogIndex), Leader 任期号(Term)也包含在其中。如果 Follower 在它的日志中找不到包含相同索引位置和任期号的条目,那么它就会拒绝接收新的日志条目,因为出现这种情况说明 Follower和Leader 不一致。

第三阶段:Leader 等待 Followers 回应。

Followers接收到Leader 发来的复制请求后,有两种可能的回应:

  • 写入本地日志中,返回 Success;
  • 一致性检查失败,拒绝写入,返回 False。

当Leader收到大多数Followers的回应后,会将第一阶段写入的Entry 标记为提交状态Committed,并把这条日志条目应用到它的状态机中。

  • 如何解决 Leader 与 Follower 不一致的问题

正常情况下,Leader和 Follower的日志保持一致。特殊崩溃情况会使它们的日志处于不一致状态。有三种情况:

  • 1)Follower落后新的leader,丢失一些在新的 Leader 中有的日志条目;
  • 2)Follower领先新的leader,有一些 Leader 没有的日志条目;
  • 3)或者两者都发生。丢失或者多出日志条目可能会持续多个任期。

要使 Follower 的日志与 Leader 恢复一致,Leader 必须找到最后两者达成一致的地方(就是回溯,找到两者最近的一致点),然后删除从那个点之后的所有日志条目,发送自己的日志给 Follower。Leader 为每一个 Follower 维护一个 nextIndex,它表示下一个需要发送给 Follower 的日志条目的索引地址。当一个 Leader 刚获得权力的时候,它初始化所有的 nextIndex 值,为自己的最后一条日志的 index 加 1。如果一个 Follower 的日志和 Leader 不一致,那么在下一次附加日志时一致性检查就会失败。在被 Follower 拒绝之后,Leader 就会减小该 Follower 对应的 nextIndex 值并进行重试。最终 nextIndex 会在某个位置使得 Leader 和 Follower 的日志达成一致。当这种情况发生,附加日志就会成功,这时就会把 Follower 冲突的日志条目全部删除并且加上 Leader 的日志。一旦附加日志成功,那么 Follower 的日志就会和 Leader 保持一致,并且在接下来的任期继续保持一致。

第四阶段:Leader 回应客户端

完成前三个阶段后,Leader会向客户端回应 OK,表示写操作成功。

第五阶段,Leader 通知Followers Entry已提交

Leader 回应客户端后,将随着下一个心跳通知 Followers,Followers 收到通知后也会将 Entry 标记为提交状态。至此,Raft 集群超过半数节点已经达到一致状态,可以确保强一致性。

2.1.3 raft safety保证

1、选举安全election safety。在一个term内,至多有一个leader被选举出来。raft算法通过一个节点某一任期内最多只能投一票;只有获得majority投票的节点才会成为leader来保障;

2、日志匹配log matching。两个节点上的某个log entry的log index相同且term相同,那么在该index之前的所有log entry应该都是相同的。leader在某一term的任一位置只会创建一个log entry,且log entry是append-only。

3、连续性检查consistency check。leader在AppendEntries中包含最新log entry之前的一个log 的term和index,如果follower在对应的term index找不到日志,那么就会告知leader不一致。当出现了leader与follower不一致的情况,leader强制follower复制自己的log。

4、leader completeness。如果一个log entry在某个任期被提交(committed),那么这条日志一定会出现在所有更高term的leader的日志里面。通过:1)一个日志被复制到majority节点才算committed;2)一个节点得到majority的投票才能成为leader,而节点A给节点B投票的其中一个前提是,B的日志不能比A的日志旧。

5、stale leader。落后的leader,但在网络分割(network partition)的情况下,可能会出现两个leader,但两个leader所处的任期是不同的。而在raft的一些实现或者raft-like协议中,leader如果收不到majority节点的消息,那么可以自己step down,自行转换到follower状态。

6、leader crash。新的节点成为Leader,为了不让数据丢失,希望新Leader包含所有已经Commit的Entry。为了避免数据从Follower到Leader的反向流动带来的复杂性,Raft限制新Leader一定是当前Log最新的节点,即其拥有最多最大term的Log Entry。

7、状态机安全State Machine Safety。某个leader选举成功后,不会直接提交前任leader时期的日志,而是通过提交当前任期的日志的时候“顺手”把之前的日志也提交了,具体的实现是:如果leader被选举后没有收到客户端的请求呢,在任期开始的时候发立即尝试复制、提交一条空的log。

2.2 log replication约束

一个log被复制到大多数节点,就是committed,保证不会回滚。leader一定包含最新的committed log,因此leader只会追加日志,不会删除覆盖日志。不同节点,某个位置上日志相同,那么这个位置之前的所有日志一定是相同的 Raft never commits log entries from previous terms by counting replicas.

3. zab协议算法

ZAB(Zookeeper Atomic Broadcast),是为zk专门设计的一种支持崩溃恢复的原子广播协议,是Zookeeper保证数据一致性的核心算法。Zab借鉴了Paxos算法,包括两种基本的模式,分别是:

  • 消息原子广播(保证数据一致性)
  • 崩溃恢复(解决2pc算法的单点问题)

集群启动或者Leader服务器出现网络中断、崩溃退出或重启等异常时,ZAB协议就会进入崩溃恢复模式,选举产生新的Leader。当选举产生了新的 Leader,同时集群中有过半的机器与该 Leader 服务器完成了状态同步(即数据同步)之后,ZAB协议就会退出崩溃恢复模式,进入消息广播模式。如果一台新的服务器加入集群,因为此时集群中已经存在一个Leader服务器在广播消息,那么该新加入的服务器自动进入恢复模式:找到Leader服务器,并且完成数据同步。同步完成后,作为新的Follower一起参与到消息广播流程中。

3.1 一些基本概念

  • electionEpoch:每一次leader选举,electionEpoch就会自增,用来标记leader选举的轮次;
  • peerEpoch:每次leader选举完成之后,都会选举出一个新的peerEpoch,用来标记事务请求所属的轮次;
  • zxid:事务请求的唯一标记,由leader服务器负责进行分配高32位是上述的peerEpoch,低32位是请求的计数,从0开始。
  • lastprocessZxid:最后一次commit的事务请求的zxid;
  • LinkedList committedLog、long maxCommittedLog、long minCommittedLog:ZooKeeper会保存最近一段时间内执行的事务请求议案,个数限制默认为500个议案。committedLog就是用来保存议案的列表,maxCommittedLog表示最大议案的zxid,minCommittedLog表示committedLog中最小议案的zxid。
  • ConcurrentMap outstandingProposals:Leader拥有的属性,每当提出一个议案,都会将该议案存放至outstandingProposals,一旦议案被过半认同了,就要提交该议案,则从outstandingProposals中删除该议案
  • ConcurrentLinkedQueue toBeApplied:Leader拥有的属性,每当准备提交一个议案,就会将该议案存放至该列表中,一旦议案应用到ZooKeeper的内存树中了,然后就可以将该议案从toBeApplied中删除。
  • recvQueue:消息接收队列,用于存放那些从其他服务器接收到的消息。
  • queueSendMap:消息发送队列,用于保存那些待发送的消息,按照SID进行分组。
  • senderWorkerMap:发送器集合,每个SenderWorker消息发送器,都对应一台远程Zookeeper服务器,负责消息的发送,也按照SID进行分组。
  • lastMessageSent:最近发送过的消息,为每个SID保留最近发送过的一个消息。

在ZAB协议中,服务节点的状态state有四种:

  • LOOKING:进入leader选举状态
  • FOLLOWING:leader选举结束,进入follower状态
  • LEADING:leader选举结束,进入leader状态
  • OBSERVING:处于观察者状态

3.2 zab算法描述

zab协议崩溃恢复模式拆分为选举阶段数据同步阶段,消息广播对应消息广播阶段。

3.2.1 选举阶段

选举过程关注两个要点:刚启动进行leader选举和选举万leader后,刚启动的server怎么感知到leader。投票过程有两个比较重要的数据:

  • HashMap recvset:用于收集LOOKING、FOLLOWING、LEADING状态下的server的投票。
  • HashMap outofelection:用于收集FOLLOWING、LEADING状态下的server的投票(说明leader选举已经完成)

1、服务器先自增electionEpoch,给自己投票。从快照日志和事务日志中加载数据,得到本机器的内存树数据,以及lastProcessedZxid。投票内容为

  • proposedLeader:server自身的myid值,初始为本机器的id;
  • proposedZxid:最大事务zxid,初始为本机器的lastProcessedZxid;
  • proposedEpoch:peerEpoch值,由上述的lastProcessedZxid的高32得到

然后向所有的服务器发送投票。

2、server接收到投票通知后,进行PK。

如果收到的通知中的electionEpoch比自己的大,则更新自己的electionEpoch为serverA的electionEpoch;如果、收到的通知中的electionEpoch比自己的小,则向serverA发送一个通知,将自己的投票以及electionEpoch发送给serverA,serverA收到后就会更新自己的electionEpoch。如果electionEpoch相同,PK的规则是proposedZxid,然后再是myId。

3、根据server的状态来判定leader

如果当前发来的投票的server的状态是LOOKING状态,则只需要判断本机器的投票是否在recvset中过半了,如果过半了则说明leader选举就算成功了,如果当前server的id等于上述过半投票的proposedLeader,则说明自己将成为了leader,否则自己将成为了follower。

如果当前发来的投票的server的状态是FOLLOWING、LEADING状态,则说明leader选举过程已经完成了,则发过来的投票就是leader的信息,这里就需要判断发过来的投票是否在recvset或者outofelection中过半了,同时还要检查leader是否给自己发送过投票信息,从投票信息中确认该leader是不是LEADING状态。

3.2.2 数据同步

一旦leader选举完成,就开始进入恢复阶段,就是follower要同步leader上的数据信息。

1、通信初始化。leader会创建一个ServerSocket,接收follower的连接,leader会为每一个连接会用一个LearnerHandler线程来进行服务;

2、重新选举出一个新的peerEpoch。follower会向leader发送一个Leader.FOLLOWERINFO信息,包含自己的peerEpoch信息。leader的LearnerHandler会获取到上述peerEpoch信息,从中选出一个最大的peerEpoch,然后加1作为新的peerEpoch。然后leader所有LearnerHandler会向各自的follower发送一个Leader.LEADERINFO信息,包含上述新的peerEpoch;follower会使用上述peerEpoch来更新自己的peerEpoch,同时将自己的lastProcessedZxid发给leader,leader的根据这个lastProcessedZxid和leader的lastProcessedZxid之间的差异进行同步。

3、已经处理的事务议案的同步。判断LearnerHandler中的lastProcessedZxid是否在minCommittedLog和maxCommittedLog之间。存在以下情况:

  • 如果LearnerHandler中的lastProcessedZxid和leader的lastProcessedZxid一致,则说明已经保持同步了;
  • 如果lastProcessedZxid在minCommittedLog和maxCommittedLog之间,从lastProcessedZxid开始到maxCommittedLog结束的这部分议案,重新发送给该LearnerHandler对应的follower,同时发送对应议案的commit命令。
  • 如果lastProcessedZxid虽然在min和max commited之间,但是并没有找到lastProcessedZxid对应的议案,即这个zxid是leader所没有的,此时的策略就是完全按照leader来同步,删除该follower这一部分的事务日志,然后重新发送这一部分的议案,并提交这些议案
  • 如果lastProcessedZxid大于maxCommittedLog,则删除该follower大于部分的事务日志;
  • 如果lastProcessedZxid小于minCommittedLog,则直接采用快照的方式来恢复

4、未处理的事务议案的同步。LearnerHandler会从leader的toBeApplied数据中将大于该LearnerHandler中的lastProcessedZxid的议案进行发送和提交(toBeApplied是已经被确认为提交的),LearnerHandler还会从leader的outstandingProposals中大于该LearnerHandler中的lastProcessedZxid的议案进行发送,但是不提交(outstandingProposals是还没被被确认为提交的)。

5、将LearnerHandler加入到正式follower列表中,LearnerHandler发送Leader.NEWLEADER以及Leader.UPTODATE命令。follower接收到之后,开始和leader进入Broadcast处理过程。leader开始进入心跳检测过程,不断向follower发送心跳命令,不断检是否有过半机器进行了心跳回复,如果没有过半,则执行关闭操作,开始进入leader选举状态;

3.2.3 消息广播broadcasting

leader收到客户端的数据后,通知所有follower;follower收到事务处理消息后,保存事务记录到history中,并且返回响应给leader,告知已收到写事务;leader收到大多数follower的响应后,就会发起提交,通知所有follower去提交事务。然后重复上述流程,直到leader出现异常。

  • 第一阶段 Propose:Leader 收到来自客户端新的事务请求后,会生成对应的事务 Proposal,并根据 zxid 的顺序(递增)向追随自己的所有 Follower 发送 P>。
  • 第二阶段 Ack:Follower 根据收到消息的次序来处理这些 Proposal,并追加到 History中,然后反馈给 Leader。
  • 第三阶段 Commit:一旦 Follower 收到来自 Leader 的 Commit(epoch, )消息,将调用 abdeliver() 提交事务 。需要注意的是,此时 Follower 必定提交了 z' < z 之前的事务。

在进入消息广播阶段后,Leader 会为每一个 Follower 分配一个 FIFO 形式的队列进行通信,确保了同一时刻一个 Follower 只能和一个 Leader 保持同步,Leader 和 Follower 彼此之间通过心跳检测来感知。这个过程会一直持续,直到

  • Leader 掉线了,Follower 的心跳包会超时,然后 Follower 进入 Looking 状态。
  • Leader 没有过半的 Follower 追随了,Leader 自己进入 Looking 状态,追随它的 Follower 也会转为 Looking 状态。

3.3 其他

3.3.1 事务持久化和恢复过程

事务持久化分为:broadcasting持久化和leader shutdown过程的持久化。

  • leader针对每次事务请求都会生成一个议案,然后向所有的follower发送该议案。follower收到提案后,将该议案记录到事务日志中,每当记满100000个(默认),则事务日志执行flush操作,同时开启一个新的文件来记录事务日志。同时会执行内存树的快照,snapshot.[lastProcessedZxid]作为文件名创建一个新文件,快照内容保存到该文件中。
  • 一旦leader过半的心跳检测失败,则执行shutdown方法,在该shutdown中会对事务日志进行flush操作

事务的恢复分为快照恢复和日志恢复。

  • 快照恢复:会在事务快照文件目录下找到最近的100个快照文件,并排序,最新的在前;对上述快照文件依次进行恢复和验证,一旦验证成功则退出,否则利用下一个快照文件进行恢复。恢复完成更新最新的lastProcessedZxid;
  • 事务日志的恢复:从事务日志文件目录下找到zxid大于等于上述lastProcessedZxid的事务日志,然后对上述事务日志进行遍历,应用到ZooKeeper的内存树中,同时更新lastProcessedZxid,同时将上述事务日志存储到committedLog中,并更新maxCommittedLog、minCommittedLog。

参考链接:

https://www.jianshu.com/p/ab4a33989a98

ZooKeeper的一致性算法赏析 - 乒乓狂魔 - OSCHINA - 中文开源技术交流社区

Zookeeper系列(3)--Paxos算法的原理及过程透彻理解_冷面寒枪biu的博客-CSDN博客_zookeeper算法

一文搞懂Raft算法 - xybaby - 博客园 

你可能感兴趣的:(中间组件,详解paxos,详解raft算法,详解zab算法,共识算法)