Zookeeper - ZAB协议 - 有主写

Posted 倪倪N

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zookeeper - ZAB协议 - 有主写相关的知识,希望对你有一定的参考价值。


文章目录

前置知识点

📢在开始ZAB协议之前先跟兄弟们一起回顾一些知识点

协调者(Leader):主节点

参与者(Follower):从节点

二阶段提交

2PC,是Two-Phase Commit的缩写,即二阶段提交,是计算机网络尤其是在数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务处理过程中能够保持原子性一致性而设计的一种算法。通常,二阶段提交协议也被认为是一种一致性协议,用来保证分布式系统数据的一致性。目前,绝大部分的关系型数据库都是采用二阶段提交协议来完成分布式事务处理的,利用该协议能够非常方便地完成所有分布式事务参与者协调统一决定事务的提交回滚,从而能够有效地保证分布式数据一致性,因此二阶段提交协议被广泛地应用在许多分布式系统中。

二阶段提交执行流程

一阶段:提交事务请求

1、事务询问

协调者所有参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应

2、执行事务

参与者节点执行事务操作,并将UndoRedo信息记入事务日志中。

3、参与者向协调者反馈

如果各参与者成功执行了事务操作,那么就反馈给协调者Yes响应,表示事务可以执行;如果参与者没有成功执行事务,那么就反馈给协调者No响应,表示事务不可以执行。

二阶段:执行事务提交

事务提交

协调者接收到所有参与者的ACK消息都是YES,执行事务提交

  • 1、发送提交申请

    协调者参与者发出Commit请求

  • 2、事务提交

    参与者收到Commit请求后,执行事务提交,完成后释放整个事务执行期间占用的事务资源

  • 3、反馈结果

    参与者在完成事务提交后,给协调者发送ACK消息

  • 4、事务完成

    协调者接收到所有参与者反馈的ACK消息后,事务完成

如图:

一阶段:

二阶段

事务中断

任何一个参与者反馈了NO,或者等待超时了导致协调者没有接收到所有参与者的反馈就会中断事务

  • 1、发送回滚请求

    协调者所有参与者发送Rollback请求

  • 2、事务回滚

    参与者接收到Rollback请求后,会根据一阶段中的Undo日志进行事务回滚,

  • 3、事务回滚结果反馈

    参与者在完成回滚后,向协调者发送ACK消息

  • 4、中断事务

    协调者接收到所有参与者反馈的ACK消息后完成事务中断

如图:

一阶段

二阶段

ZAB协议

Zookeeper 是通过 Zab 协议来保证分布式事务的最终一致性

ZAB又名原子广播协议(Zookeeper Atomic Broadcast ) 作用在可用状态有Leader

  • 原子:要么成功,要么失败,没有中间状态(FIFO队列+类似2PC操作)

  • 广播:分布式多节点的,所以执行操作都是由Leader(协调者)向所有Follower(参与者)统一发送请求

PS:

  • ZK的数据状态存储在内存

  • ZK是日志存储在磁盘

一主两从环境下写操作为例展开讨论
如图(由于要连很多线条,所以没有用类似上方两阶段提交中的上下结构布局):

  • 第一步:在ZK客户端对任意一个Follower节点执行一个写操作create /rhys "aaa"

  • 第二步:Follower节点将这笔写操作转发给Leader节点

  • 第三步:Leader会创建一个事务ID(zxid),假设本次给出的事务ID为1

  • 第四步:其实在Leader对于每个Follower都维护着一个发送队列(FIFO队列),紧接着Leader会给两台Follower发起关于创建XXX节点这件事第一阶段操作写日志,那么这个写日志操作就会先入发送队列。再顺序执行队列中操作,当写日志操作执行成功后,Follower会返回一个ok/yes的状态,那对应的Leader中也会生成一个ok/yes的状态,由于我们是一主两从,那有了两台机返回了ok状态,满足了过半通过条件 (3/2+1),这时Leader会再次对两台Follower发起第二阶段write写内存操作,其实就是类似两阶段提交(2PC),只是这里的两阶段提交开始回顾的两阶段提交不一样的地方时没有中断事务操作,因为这里的两阶段提交不需要接收到所有Follower(参与者)的ACK反馈,只需要超过一半的机器ACK就可以了,依然是入发送队列,然后从队列中顺序执行操作,操作完成同样的会返回一个ok/yes状态,达到过半条件则Leader会给Follower返回一个over-ok状态,再由Follower传递给客户端

📢兄弟🚪这边有一点需要提一下,我们刚提到过半提交这个概念对吧,那另一台Follower机器没有返回ok状态,对应的发送队列依旧会放入一个write操作,只要最终那台没有返回okFollower机器能把队列中操作消费完,那这个节点的数据最终还是会跟其他两个节点保持一致的,这边就体现出了最终一致性

  • 总结:回过头再看ZAB的原子没有中间状态其实就是依据FIFO队列+类似2PC操作,广播其实就是体现了过半通过的概念

Zookeeper的ZAB协议

一、ZAB协议(原子消息广播协议)

??ZAB(Zookeeper Atomic Broadcast)协议是Zookeeper用来保证其数据一致性的核心算法,是一种支持崩溃恢复的原子广播协议。基于此协议,Zookeeper实现了一种主备模式的系统架构来保持集群中各副本之间数据的一致性。

1.1、ZAB协议的作用

  • 事务处理:ZAB协议要求Zookeeper中使用一个单一的主进程来接收并处理客户端的所有事务请求,并采用ZAB的原子广播协议,将服务器数据的状态变更以Proposal的形式广播到所有的副本进程上去。使用同一时刻集群中只有一个主进程来广播服务器状态变更的方式,可以很好的处理客户端大量的并发请求。

  • 变更顺序应用:ZAB协议用于保证一个全局的变更序列被顺序的应用。就是说如果一个状态变更已经被处理成功,那么所有其依赖的状态变更都应该被提前处理成功了。

  • 容错性:当主进程出现崩溃退出或者异常重启时,ZAB协议应保证集群依旧能对外提供正常服务。

1.2、ZAB协议的核心

??ZAB协议的核心定义了事务请求的处理方式,具体:

??所有的事务请求必须由一个全局唯一的服务器来协调处理,该服务器就是 Leader服务器。剩余的服务器则是 Follower服务器。

??Leader服务器负责将客户端的一个事务请求,转换成一个事务Proposal,并将该 Proposal 分发给集群中所有的 Follower 服务器,即发送数据广播请求。

??广播后Leader服务器需要等待所有Follower服务器的反馈(Ack请求)。Zab协议规定,只要超过半数的Follower服务器进行了正确的Ack反馈请求后,Leader 就可以再次向所有的Follower服务器发送 Commit 消息,要求其将上一个 事务proposal 进行提交。

技术图片

二、ZAB协议的两种模式

2.1、消息广播模式

2.1.1、运行时机

??当集群中已经有过半的follower与leader服务器完成了状态同步,那么整个zk集群就可以进入消息广播模式了。

2.1.1、运行过程

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

??ZAB协议将二阶段提交中的中断逻辑移除。就是说对于一个Proposal请求,只要过半的Follower服务器已经反馈Ack之后,Leader就开始提交事务Proposal了。这样就产生了一个问题:无法处理Leader服务器崩溃退出而带来的数据不一致问题的。
??解决方案:ZAB协议的崩溃恢复模式。
??另外,整个消息传播协议是基于具有FIFO特性的TCP协议来进行网络通信的,能够很容易的保证消息广播过程中消息接收与发送的顺序性。

??在消息广播过程中,Leader服务器会为每一个Follower服务器都各自分配一个单独的队列,然后将需要广播的事务Proposal依次放入这些队列中去,并且根据FIFO策略进行消息发送。每一个Follower服务器在接收到这个事务Proposal之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且在成功写入后反馈给Leader服务器一个Ack响应。当Leader服务器接收到超过半数Follower的Ack响应后,就会广播一个Commit消息给所有的Follower服务器以通知其进行事务提交,同时Leader自身也会完成对事务的提交,而每一个Follower服务器在接收到Commit消息后,也会完成对事务的提交。

Zookeeper节点消息广播流程图:
技术图片

2.2、崩溃恢复模式

2.2.1、运行时机

??一旦Leader服务器出现崩溃,或者说由于网络原因导致Leader服务器失去了与过半Follower联系,那么就会进入崩溃恢复模式。

2.2.2、Leader选举算法

??为了保证程序的正确运行,恢复过程结束后需要选举出一个新的Leader服务器,这就是Leader选举算法的作用。除此之外,该算法还需要确保:

  • ZAB 协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器都提交。
    ??假设一个事务在Leader服务器上被提交了,并且已经得到过半Follower服务器的Ack反馈,但是在他将Commit消息发送给所有Follower机器之前,Leader服务器挂了,如下图所示。
    技术图片
    ??上图的消息C2就是一个典型的例子:在集群正常运行过程中的某一个时刻,Server 1 是Leader服务器,其先后广播了消息P1、P2、C1、P3和C2,其中,当Leader服务器将消息C2(C2是Commit Of Proposal2的缩写,即提交事务Proposal2)发出后就立即崩溃退出了。针对这种情况,ZAB协议就需要确保事务Proposal2最终能够在所有的服务器上都被提交成功,否则将出现不一致。

  • ZAB协议需要确保丢弃那些只在Leader服务器上被提出的事务。
    ??相反,如果在崩溃恢复过程中出现一个需要被丢弃的提案,那么在崩溃恢复结束后需要跳过该事务Proposal,如下图所示。
    技术图片
    ??在上图所示的集群中,假设出事的Leader服务器Server1 在提出了一个事务Proposal3之后就崩溃退出了,从而导致集群中的其他服务器都没有收到这个事务Proposal。于是,当Server1恢复过来再次加入到集群中的时候,ZAB协议需要确保丢弃Proposal3这个事务。

??解决方案:为了确保提交已经被Leader提交的事务Proposal,同时丢弃已经被跳过的事务Proposal。Leader选举算法规定:保证新选举出来的Leader服务器拥有集群中所有机器最高编号(即ZXID最大)的事务Proposal,那么就可以保证这个新选举出来的Leader一定具有所有已经提交的提案。更为重要的是,如果让具有最高编号事务Proposal的机器来成为Leader,就可以省去Leader服务器检查Proposal的提交和丢弃工作的这一步操作了。

Leader选举的详细过程:https://www.cnblogs.com/leesf456/p/6107600.html

2.2.2、数据同步

??完成Leader选举之后,在正式开始工作(即接收客户端的事务请求,然后提出新的提案)之前,Leader服务器会首先确认事务日志中的所有Proposal是否都已经被集群中过半的机器提交了,即是否完成数据同步。ZAB协议的数据同步过程:

??Leader服务器会为每一个Follower服务器都准备一个队列,将没有被Follower服务器同步的事务以Proposal消息的形式逐个发送给Follower,并在每一个Proposal消息后面紧接着再发送一个Commit消息,以表示该事务已经被提交。等到Follower服务器将所有其尚未同步的事务Proposal都从Leader服务器上同步过来并成功应用到本地数据库中后,Leader服务器就会将该Follower服务器加入到真正的可用Follower列表中,并开始之后的其他流程。

??上面是正常情况下的数据同步逻辑。对于需要被丢弃的事务Proposal:在ZAB协议的事务编号ZXID设计中,ZXID是一个64位的数字,其中低32位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader服务器在产生一个新的事务Proposal的时候,都会对该计数器进行加1操作;而高32位则代表了Leader周期epoch的编号,每当选举产生一个新的Leader服务器,就会从这个Leader服务器上取出其本地日志汇总最大事务Proposal的ZXID,并从该ZXID中解析出对应的epoch值,然后再对其进行加1操作,之后就会以此编号作为新的epoch,并将32位置0来开始生成新的ZXID。ZAB协议中的这一通过epoch编号来区分Leader周期变化的策略,能有效地避免不同的Leader服务器错误的使用相同的ZXID编号提出不一样的事务Proposal的异常情况。

??基于此策略,当一个包含了上一个Leader周期中尚未提交过的事务Proposal的服务器启动时,其肯定无法成为Leader,原因很简单,因为当前集群中一定包含一个Quorum集合,该集合中的机器一定包含了更高epoch的事务Proposal,因此这台机器的事务Proposal肯定不是最高,也就是无法成为Leader了。当这台机器加入到集群中,以Follower角色连接上Leader之后,Leader会根据自己服务器上最后被提交的Proposal来和Follower的Proposal进行比对,比对的结果当然是Leader会要求Follower进行一个回退操作——回退到一个确实已经被集群中过半机器提交的最新的事务Proposal。

  • 作者: DeepInThought
    出处: https://www.cnblogs.com/DeepInThought
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 以上是关于Zookeeper - ZAB协议 - 有主写的主要内容,如果未能解决你的问题,请参考以下文章

    Zab协议:Zookeeper一致性协议

    Zookeeper的ZAB协议

    zookeeper中的ZAB协议理解

    Zookeeper——一致性协议:Zab协议

    zookeeper(16)源码分析-ZAB协议

    Zookeeper深入原理(3) - Zab协议