ZAB协议

一:协议核心

1:崩溃恢复 ,消息广播

2:Zab 节点有三种状态:

Following:当前节点是跟随者,服从 Leader 节点的命令

Leading:当前节点是 Leader,负责协调事务

Election/Looking:节点处于选举状态,正在寻找 Leader

3:Zab 的四个阶段

选举阶段(Leader Election)

Zookeeper 规定所有有效的投票都必须在同一个 轮次 中,每个服务器在开始新一轮投票时,都会对自己维护的 logicalClock 进行自增操作。

发现阶段(Descovery)

主要目的是发现当前大多数节点接收的最新 Proposal,并且准 Leader 生成新的 epoch ,让 Followers 接收,更新它们的 acceptedEpoch

同步阶段(Synchronization)

同步阶段主要是利用 Leader 前一阶段获得的最新 Proposal 历史,同步集群中所有的副本。

广播阶段(Broadcast)

到了这个阶段,Zookeeper 集群才能正式对外提供事务服务,并且 Leader 可以进行消息广播。同时,如果有新的节点加入,还需要对新节点进行同步

 

二:协议过程

当整个集群启动过程中,或者当 Leader 服务器出现网络中弄断、崩溃退出或重启等异常时,Zab协议就会 进入崩溃恢复模式,选举产生新的Leader。当选举产生了新的 Leader,同时集群中有过半的机器与该 Leader 服务器完成了状态同步(即数据同步)之后,Zab协议就会退出崩溃恢复模式,进入消息广播模式。

如果有一台遵守Zab协议的服务器加入集群,因为此时集群中已经存在一个Leader服务器在广播消息,那么该新加入的服务器自动进入恢复模式:找到Leader服务器,并且完成数据同步。同步完成后,作为新的Follower一起参与到消息广播流程中

 

三:消息广播

ZAB协议的消息广播过程使用的是一个原子广播协议,类似于一个2PC提交过程,针对每个客户端的事务请求,leader服务器会为其生成对应的事务Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各自的选票,最后进行事务提交。

流程:

1:Leader 接收到消息请求后,将消息赋予一个全局唯一的 64 位自增 id,叫做:zxid,通过 zxid 的大小比较即可实现因果有序这一特性

2:Leader 通过先进先出队列(会给每个follower都创建一个队列,保证发送的顺序性)(通过 TCP 协议来实现,以此实现了全局有序这一特性)将带有 zxid 的消息作为一个提案(proposal)分发给所有 follower

3:当 follower 接收到 proposal,先将 proposal 写到本地事务日志,写事务成功后再向 leader 回一个 ACK

4:当 leader 接收到过半的 ACKs 后,leader 就向所有 follower 发送 COMMIT 命令,同意会在本地执行该消息

5:当 follower 收到消息的 COMMIT 命令时,就会执行该消息

相比于完整的二阶段提交,Zab 协议最大的区别就是移除了中断逻辑,follower 要么回 ACK 给 leader,要么抛弃 leader,在某一时刻,leader 的状态与 follower 的状态很可能不一致,因此它不能处理 leader 挂掉的情况,所以 Zab 协议引入了恢复模式来处理这一问题。从另一角度看,正因为 Zab 的广播过程不需要终止事务,也就是说不需要所有 follower 都返回 ACK 才能进行 COMMIT,而是只需要合法数量(2f+1 台服务器中的 f+1 台) 的follower,也提升了整体的性能。

不能正常反馈的就节点就抛弃leader,然后进入数据同步阶段,和集群达成一致。

 

四:崩溃恢复

Leader选举

1:ZAB协议会让ZK集群进入崩溃恢复模式的3种情况:

      1:当服务框架在启动过程中

      2:当Leader服务器出现网络中断,崩溃退出与重启等异常情况。

      3:当集群中已经不存在过半的服务器与Leader服务器保持正常通信。

2:选举算法 :zk的实现是FastLeaderElection算法。

3:Leader选举需要达到的再次使用的条件,需要解决以下两个问题:

  1:已经被处理的事务请求(proposal)不能丢(commit的)

     2:没被处理的事务请求(proposal)不能再次出现

什么时候会出现事务请求被丢失呢?

  当 leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回「成功」。但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息。

3.1:如何解决 已经被处理的事务请求(proposal)不能丢(commit的)呢?

1:选举拥有 proposal 最大值(即 zxid 最大) 的节点作为新的 leader:由于所有提案被 COMMIT 之前必须有合法数量的 follower ACK,即必须有合法数量的服务器的事务日志上有该提案的 proposal,因此,zxid最大也就是数据最新的节点保存了所有被 COMMIT 消息的 proposal 状态。

2:新的 leader 将自己事务日志中 proposal 但未 COMMIT 的消息处理。 3:新的 leader 与 follower 建立先进先出的队列, 先将自身有而 follower 没有的 proposal 发送给 follower,再将这些 proposal 的 COMMIT 命令发送给 follower,以保证所有的 follower 都保存了所有的 proposal、所有的 follower 都处理了所有的消息。通过以上策略,能保证已经被处理的消息不会丢。

 

3.2:如何解决没被处理的事务请求(proposal)不能再次出现

    当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal,因此经过恢复模式重新选了 leader 后,这条消息是被跳过的。 此时,之前挂了的 leader 重新启动并注册成了 follower,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的,需要将其删除。

解决方案是:

 Zab 通过巧妙的设计 zxid 来实现这一目的。一个 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 生成初始化事务集合)

1:所有follower 向准leader 发送自己最后接收的事务的epoch;

2:准leader 选取最大的epoch,加1得到e1,将e1 发送给follower;

3:follower 收到准leader 发送的epoch 值之后,与自己的epoch 值作比较,若小于,则将自己的epoch 更新为e1,并向准leader 发送反馈ACK信息(epoch 信息、历史事务集合);

4:准leader 接收到ACK 消息之后,会在所有历史事务集合中选择其中一个历史事务集合作为初始化事务集合,该事务集合满足ZXID最大;

第二阶段(数据同步)

1:准leader 将epoch 与 初始化事务集合发送给集群中过半的follower;每个follower 会分配到一个队列,leader 会将那些没有被各个follower 同步的事务以proposal 形式发送给各个follower,并在后面追加commit 消息,表示事务已被提交;

2:follower 接收后,会执行初始化事务集合中的事务(执行过跳过,未执行执行),反馈给leader 表明自己已经处理(追上来了)

3:leader 收到后过半反馈后,发送commit 消息;

4:follower 接收到commit 消息后,提交事务;

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值