ZooKeeper系列之ZAB协议

news2025/2/22 8:03:35

概述

ZooKeeper Atomic Broadcast,ZooKeeper原子消息广播协议。ZAB协议是为分布式协调服务ZK专门设计的一种支持崩溃恢复的原子广播协议。ZK主要依赖ZAB协议来实现分布式数据的最终一致性,基于该协议,ZK实现一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。

集群角色

  1. Leader:同一时间集群总只允许有一个Leader,提供对客户端的读写功能,负责将数据同步至各个节点;
  2. Follower:提供对客户端读功能,写请求则转发给Leader处理,当Leader崩溃失联之后参与Leader选举;
  3. Observer:与Follower不同的是但不参与Leader选举

运行时状态

对应于org.apache.zookeeper.server.quorum.QuorumPeer.ServerState枚举类,ZAB协议的Java实现都是在这个包下面,下文不再写全路径名:

public static enum ServerState {
    LOOKING,
    FOLLOWING,
    LEADING,
    OBSERVING;
}

进程的可能状态:

  1. LOOKING:Leader选举状态,正在寻找Leader
  2. FOLLOWING:当前节点是Follower。与Leader服务器保持同步状态
  3. LEADING:当前节点是Leader,作为主进程领导状态
  4. OBSERVING:observer角色

ZAB状态

ZK给ZAB定义的4种状态,反应ZK从选举到对外提供服务的过程中的四个步骤。状态枚举源码:

public enum ZabState {
    ELECTION,
    DISCOVERY,
    SYNCHRONIZATION,
    BROADCAST
}
  1. ELECTION:集群进入选举状态,此过程会选出一个节点作为Leader角色;
  2. DISCOVERY:连接上Leader,响应Leader心跳,并且检测Leader的角色是否更改,通过此步骤之后选举出的Leader才能执行真正职务;
  3. SYNCHRONIZATION:整个集群都确认Leader之后,将会把Leader的数据同步到各个节点,保证整个集群的数据一致性;
  4. BROADCAST:过渡到广播状态,集群开始对外提供服务。

状态切换

  1. 启动时的状态转换

    • 所有进程的初始状态都是LOOKING状态,此时不存在Leader
    • 接下来,进程会试图选举出来一个新的Leader,Leader切换为LEADING状态,其它进程发现已经选举出新的Leader,那么它就会切换到FOLLOWING状态,并开始与Leader保持同步
    • 处于FOLLOWING状态的进程称为Follower,LEADING状态的进程称为Leader
    • 当Leader崩溃或者放弃领导地位时,其余Follower进程就会切换到LOOKING状态开始新一轮的Leader选举
  2. 运行过程中的状态转换

    • 一个Follower只能和一个Leader保持同步,Leader进程和所有的Follower进程之间通过心跳监测机制来感知彼此的情况
    • 若Leader能够在超时时间内正常的收到心跳检测,那么Follower就会一直与该Leader保持连接
    • 如果在指定时间内Leader无法从过半的Follower进程那里接收到心跳检测,或者TCP连接断开,那么Leader会放弃当前周期的领导,并转换为LOOKING状态;其他的Follower也会选择放弃这个Leader,同时转换为LOOKING状态,之后会进行新一轮的Leader选举。

Epoch

Epoch指当前集群的周期号(年代号),集群的每次Leader变更都会产生一个新的周期号,周期号的产生规则是在上一个周期号的基础上加1,这样当之前的Leader崩溃恢复后会发现自己的周期号比当前的周期号小,说明此时集群已经产生新的Leader,旧的Leader会再次以Follower的角色加入集群。

Proposal

提议,源码为Leader.Proposal,是Leader的内部类,由Leader发起选举的提议:

public static class Proposal extends SyncedLearnerTracker {
    private QuorumPacket packet;
    protected Request request;
    // 省略构造方法和getter
    public long getZxid() {
        return this.packet.getZxid();
    }
}

Vote

投票,源码:

public class Vote {
	// 默认值为0
    private final int version;
    private final long id;
    private final long zxid;
    // 默认值-1
    private final long electionEpoch;
    // 默认值-1
    private final long peerEpoch;
    // 默认值Looking
    private final QuorumPeer.ServerState state;
    // 省略构造方法和getter
}

Zxid

该协议主要通过唯一的事务编号Zxid(ZooKeeper Transaction id)保障集群状态的唯一性。Zxid与RDBMS中的事务id类似,用于标识一次提议的id;为了保证顺序性,Zxid必须单调递增,保证全局有序。

Zxid指ZAB协议的事务编号,一个64位的数字,低32位存储的是一个简单的单调递增的计数器,针对客户端的每一个事务请求,计数器都加1。高32位存储的是Leader的周期号Epoch。每次选举产生一个新的Leader时,该Leader都会从当前服务器的日志中取出最大事务的Zxid,获取其中高32位的Epoch值并加1,以此作为新的Epoch,并将低32位重置为0,重新开始计数。

这样设计的好处是旧的Leader宕机后重启,它不会被选举为Leader,因为此时它的Zxid肯定小于当前的新Leader。当旧的Leader作为Follower接入新的Leader后,新的Leader会让它将所有的拥有旧的epoch号的未被COMMIT的Proposal清除。

模式

ZAB协议有两种模式,分别是崩溃恢复模式(集群选主)和消息广播模式(数据同步)。

崩溃恢复

Recovery,当集群启动、集群重启、网络中断、Leader崩溃后,集群将开始选主,该过程为崩溃恢复模式。当选举产生新的Leader服务器,同时集群中已经有超过半数(ZK里定义为quorum,下同)的Follower机器与该Leader服务器完成状态(数据)同步之后,ZAB协议会退出恢复模式,即进入消息广播模式。

在ZAB协议中,为保证程序的正确运⾏,整个恢复过程结束后需要选举出⼀个新的Leader服务器。Leader选举算法不仅仅需要让Leader⾃身知道已经被选举为Leader,同时还需要让集群中的所有其他机器也能够快速感知到选举产⽣出来的新Leader服务器。

消息广播

Boardcast,广播的过程实际上是一个简化的二阶段提交过程。当Leader被选举出来后,Leader将最新的集群状态广播给其他Follower,该过程为广播模式。

当一台遵守ZAB协议的服务器启动后加入到集群中,如果此时集群中已经存在一个Leader服务器在负责进行消息广播,那么加入的服务器会自觉的进入数据恢复模式:找到Leader所在的服务器,并与其进⾏数据同步,数据同步完成后参与到消息⼴播流程中。

消息广播过程:

  • 客户端发起写请求
  • Leader将客户端请求信息转化为事务Proposal,同时为每个Proposal分配一个事务ID
  • Leader为每个Follower单独分配一个FIFO的队列,将需要广播的Proposal依次放入到队列中
  • Follower接收到Proposal后,首先将其以事务日志的方式写入到本地磁盘中,写入成功后给Leader反馈一个ACK响应
  • Leader接收到半数以上Follower的ACK响应后,即认为消息发送成功,可以发送Commit消息
  • Leader向所有Follower广播Commit消息,同时自身也会完成事务提交。Follower接收到Commit消息后也会完成事务的提交
    在这里插入图片描述

数据一致性

ZAB协议规定:如果⼀个事务Proposal在⼀台机器上被处理成功,则在所有的机器上都被处理成功,哪怕机器出现故障崩溃。

数据同步:所有正常运行的服务器要么成为Leader,要么成为Follower并和Leader保持同步。

  • 完成Leader选举(新的Leader具有最高的zxid)之后,在正式开始⼯作(接收客户端请求)之前,Leader服务器会⾸先确认事务⽇志中的所有Proposal是否已经被集群中过半的机器提交,即是否完成数据同步。
  • Leader服务器需要确保所有的Follower服务器能够接收到每⼀条事务Proposal,并且能够正确地将所有已经提交的事务Proposal应⽤到内存数据中。等到Follower服务器将所有其尚未同步的事务Proposal都从Leader服务器上同步过来并成功应⽤到本地数据库中后,Leader服务器就会将该Follower服务器加⼊到真正的可⽤Follower列表中,并开始之后的其他流程。

ZAB的选举出来的Leader必须满足条件:
能够确保提交已经被Leader提交的事务Proposal,同时丢弃已经被跳过的事务Proposal。即:

  • 新选举出来的Leader不能包含未提交的Proposal。
  • 新选举的Leader节点中含有最大的zxid。

选举

4个阶段

ZAB的四个阶段:Leader Election领导选举、Discovery发现、Synchronization同步、Broadcast广播。

选举阶段
在集群选举开始时,所有节点都处于选举阶段。当某一个节点的票数超过半数节点后,该节点将被推选为准Leader。选举阶段的目的就是产生一个准Leader。只有到达广播阶段后,准Leader才会成为真正的Leader。

发现阶段
各个Follower开始和准Leader进行通信,同步Follower最近接收的事务提议。这时,准Leader会产生一个新的Epoch,并尝试让其他Follower接收该Epoch后再更新到本地,即更新acceptedEpoch。

发现阶段的一个Follower只会连接一个Leader,如果节点1认为节点2是Leader,则当节点1尝试连接节点2时,如果连接被拒绝,则集群会进入重新选举阶段。发现阶段的主要目的是发现当前大多数节点接收的最新提议。
在这里插入图片描述
同步阶段
主要是将Leader在前一阶段获得的最新提议信息同步到集群中所有的副本。只有当quorum都同步完成时,准Leader才会成为真正的Leader。Follower只会接收Zxid比自己的lastZxid大的提议。同步阶段完成后集群选主的操作才完成,新的Leader将产生。
在这里插入图片描述
广播阶段
ZK集群开始正式对外提供事务服务,这时Leader进行消息广播,将其上的状态通知到其他Follower,如果后续有新的节点加入,则Leader会对新节点进行状态的同步。ZAB提交事务并不像2PC一样需要全部Follower都Ack,只需要得到quorum的Ack就可以。
在这里插入图片描述

ZAB选举过程

每个Server首先都提议自己是Leader,并为自己投票,然后将投票结果与其他Server的选票进行对比,权重大的胜出,使用权重较大的选票更新自身的选票箱,具体选举过程:

  1. 每个Server启动以后都询问其他Server给谁投票,其他Server根据自己的状态回复自己推荐的Leader并返回对应的Leader id和Zxid。在集群初次启动时,每个Server都会推荐自己为Leader
  2. 当Server收到所有其他Server的回复后,计算出Zxid最大的Server,并将该Server设置成下一次要投票推荐的Server
  3. 计算过程中票数最多的Server将成为获胜者,如果获胜者的票数超过集群个数的一半,则该Server将被推选为Leader。否则,继续投票,直到Leader被选举出来
  4. Leader等待其他Server连接
  5. Follower连接Leader,将最大的Zxid发送给Leader
  6. Leader根据Follower的Zxid确定同步点,至此,选举阶段完成。

在选举阶段完成后,Leader通知其他Follower集群已经成为Uptodate状态,Follower收到Uptodate消息后,接收Client的请求并开始对外提供服务。

Java实现

ZAB协议的Java实现与其定义略有不同,在实际实现时,选举阶段采用Fast Leader Election模式。在该模式下,节点首先向所有Server提议自己要成为Leader,当其他Server收到提议以后,判断Epoch信息并接收对方的提议,然后向对方发送接收提议完成的消息。在Java的实现过程中将发现阶段和同步阶段合并为恢复阶段。因此,ZAB协议的Java实现只有3个阶段:Fast Leader Election、Recovery和Broadcast。

Fast Leader Election

简称FLE,是Java实现版的选举机制,对应源码为FastLeaderElection implements Election。Election是一个接口,有两个方法:

public interface Election {
    Vote lookForLeader() throws InterruptedException;
    void shutdown();
}

选举过程核心在lookForLeader()方法。

FLE会选举拥有最新提议的历史节点(其lastZxid最大)作为Leader,故而可省去发现最新提议的步骤。

成为leader的条件?

  1. 选epoch最大的
  2. epoch相等,选zxid最大的
  3. epoch和zxid都相等,选server_id最大的,即zoo.cfg中配置的myid

节点在选举开始时,都默认投票给自己,当接收其他节点的选票时,会根据上面的Leader条件判断并且更改自己的选票,然后重新发送选票给其他节点。当有一个节点的得票超过半数,该节点会设置自己的状态为Leading,其他节点会设置自己的状态为Following。
在这里插入图片描述

Recovery Phase

将发现阶段和同步阶段合并为恢复阶段。这一阶段Follower发送他们的lastZxid给Leader,Leader根据lastZxid决定如何同步数据。这里的实现跟前面的阶段3有所不同:Follower收到TRUNC指令会终止L.lastCommitedZxid之后的Proposal,收到DIFF指令会接收新的Proposal。
在这里插入图片描述

拓展

ZAB对比二阶段提交

ZAB协议的消息广播使用原子广播协议, 类似一个二阶段提交的过程 ,但又有所不同:

  • 二阶段提交中,需要所有参与者反馈ACK后再发送Commit请求。要求所有参与者要么成功,要么失败。这样会产生严重的阻塞问题
  • ZAB协议中,Leader等待半数以上的Follower成功反馈ACK即可,不需要收到全部的Follower反馈ACK

ZAB与Paxos的区别

相同点:

  • 都存在一个类似Leader进程的角色,由其负责协调多个Follower进程的运行
  • Leader进程都会等待超过半数的Follower作出正确的反馈后,才会将一个提议进行提交
  • 在ZAB中,每个Proposal中都包含一个epoch值,用来代表当前Leader周期,在Paxos中同样存在这样的一个表示叫Ballot

不同点:

  • Paxos算法中,新选举产生的主进程会进行两个阶段的工作;第一阶段称为读阶段:新的主进程和其他进程通信来收集主进程提出的提议,并将它们提交。第二阶段称为写阶段:当前主进程开始提出自己的提议。
  • ZAB协议在Paxos基础上添加同步阶段。此阶段,新的Leader会确保存在过半的Follower已经提交之前Leader周期中的所有事务Proposal。此阶段的引入能够有效保证,Leader在新的周期中提出事务Proposal之前,所有的进程都已经完成对之前所有事务Proposal的提交。

本质区别在于两者的设计目的不一样:ZAB协议主要用于构建一个高可用的分布式数据主备系统,而Paxos算法则用于构建一个分布式的一致性状态机系统。

问答

主从架构下,Leader崩溃,数据一致性怎么保证?
Leader崩溃后,集群会选出新的Leader,进入恢复阶段,新Leader具有所有已经提交的提议,因此它会保证让Followers同步已提交的提议,丢弃未提交的提议(以Leader的记录为准),保证整个集群的数据一致性。

选举Leader时,整个集群无法处理写请求的,如何快速进行leader选举?
通过FLE实现的,Leader选举只需要超过半数的节点投票即可,这样不需要等待所有节点的选票,能够尽早选出Leader。

参考

ZAB协议的那些事
ZAB协议
ZooKeeper是强一致的吗

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1690100.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【EI会议】2024年雷达、电子与通信工程国际会议(ICREC 2024)

2024年雷达、电子与通信工程国际会议 2024 International Conference on Radar, Electronics and Communication Engineering 【1】会议简介 2024年雷达、电子与通信工程国际会议即将在深圳隆重召开。深圳,这座充满活力的现代化都市,以其卓越的科技创新…

后端之路第二站(正片)——SprintBoot之:设置请求接口

这一篇讲怎么简单结合模拟云接口,尝试简单的后端接接口、接受并传数据 一、下载Apifox接口文档软件 目前的企业都是采用前后端分离开发的,在开发阶段前后端需要统一发送请求的接口,前端也需要在等待后端把数据存到数据库之前,自己…

微信H5跳小程序 wx-open-launch-weapp ios显示且正常跳转,安卓不显示不报错解决方案

前提:在一切都正常(无报错,没有写法错误等)的情况下,出现这个问题: 去你的h5项目,用浏览器打开,在network随便找一个静态文件,在response响应标头中找找,是否有Content-Security-Policy这个头&…

vue2流星雨(可调角度)

新建StarBackground.vue组件 打开组件注释部分可以随机颜色 <template><div class"rain"><divv-for"(item,index) in rainNumber":key"index"class"rain-item"ref"rain-item":style"transform:rotate(…

【MySQL进阶之路 | 基础篇】触发器

1. 为什么要使用触发器 我们可能会遇到如下场景.我们有两个相互关联的表&#xff0c;如商品信息表与库存信息表.当我们向商品信息表添加一条记录时&#xff0c;为了保证数据完整性&#xff0c;也必须向库存信息表添加一条数据.我们就必须把这两个关联的操作写在程序里&#xf…

【APKtool】APKtool实现某瓣APP重签名

APP name 重打包 重打包完成 开始签名 apktool签名 使用 APKtool 或其他工具生成的签名文件与原始签名文件的区别主要在于它们使用的密钥和证书可能不同。当你使用 APKtool 对 APK 文件进行反编译、修改后再重新打包时&#xff0c;你通常需要使用一个新的密钥和证书对修改后…

机器人非线性控制方法——线性化与解耦

机器人非线性控制方法是针对具有非线性特性的机器人系统所设计的一系列控制策略。其中&#xff0c;精确线性化控制和反演控制是两种重要的方法。 1. 非线性反馈控制 该控制律采用非线性反馈控制的方法&#xff0c;将控制输入 u 分解为两个部分&#xff1a; α(x): 这是一个与…

计算机毕业设计 | springboot养老院管理系统 老人社区管理(附源码)

1&#xff0c;绪论 1.1 背景调研 养老院是集医疗、护理、康复、膳食、社工等服务服务于一体的综合行养老院&#xff0c;经过我们前期的调查&#xff0c;院方大部分工作采用手工操作方式,会带来工作效率过低&#xff0c;运营成本过大的问题。 院方可用合理的较少投入取得更好…

HTML5 + CSS3模拟庆余年中“五竹”的镭射眼动画特效

庆余年2已经火热开播了&#xff0c;据说反响强烈啊&#xff0c;不知道这一部里面&#xff0c;五竹的镭射眼会不会表现出来&#xff0c;我还挺想看看他的镭射眼的&#xff0c;我看到底有没有杀死剧中的庆帝。 回想第一部&#xff0c;我都快记不清那是几年前开播的了&#xff0c;…

Ubuntu 安装 LibreOffice

1. 删除预安装的LibreOffice Ubuntu 和其他的 Linux 发行版带有预安装的 LibreOffice。这可能不是最新的&#xff0c;这是因为发行版有特定的发行周期。在进行新安装之前&#xff0c;你可以通过以下命令删除 Ubuntu 及其衍生发行版中的的旧版本。 sudo apt remove –purge li…

VScode SSH连接远程服务器报错

一、报错 通过VScode SSH插件远程连接服务器&#xff0c;输入密码后没有连接成功&#xff0c;一直跳出输入密码界面&#xff0c;在输出界面里&#xff0c;一直是Waiting for server log或者是显示Cannot not find minimist 二、处理 &#x1f431;&#xff1a; 这个时候应该…

安全工程师考试摸拟试题

安全工程师考试摸拟试题安全工程师是指在工程项目中负责安全管理和安全技术服务的专业人员。他们需要具备扎实的理论知识和丰富的实践经验&#xff0c;能够有效预防和控制各类安全风险… 1 安全工程师考试摸拟试题 安全工程师是指在工程项目中负责安全管理和安全技术服务的专业…

Vue开发实例(十三)用户登录功能

使用Vue实现登录具有以下几个好处&#xff1a; 响应式界面&#xff1a;Vue框架的响应式特性可以帮助开发者轻松地实现用户登录界面的交互效果&#xff0c;包括表单验证、实时错误提示等&#xff0c;从而提升用户体验。组件化开发&#xff1a;Vue框架支持组件化开发&#xff0c;…

pillow学习3

Pillow库中&#xff0c;图像的模式代表了图像的颜色空间。以下是一些常见的图像模式及其含义&#xff1a; L&#xff08;灰度图&#xff09;&#xff1a;L模式表示图像是灰度图像&#xff0c;每个像素用8位表示&#xff08;范围为0-255&#xff09;&#xff0c;0表示黑色&#…

国家开放大学-实验3:类、对象、方法和修饰符的使用

作业答案 联系QQ:1603277115 实验目的 通过本实验&#xff0c;了解和掌握类、方法以及各个修饰符的使用。 问题描述 基于面向对象思想和类的方式&#xff0c;创建一个计算金额的程序。 啤酒 3.5元/罐&#xff0c; 方便面 4.5元/包&#xff0c; 矿泉水 2.0 元/瓶。 优惠规…

【Linux】信号之信号的产生详解

&#x1f916;个人主页&#xff1a;晚风相伴-CSDN博客 &#x1f496;如果觉得内容对你有帮助的话&#xff0c;还请给博主一键三连&#xff08;点赞&#x1f49c;、收藏&#x1f9e1;、关注&#x1f49a;&#xff09;吧 &#x1f64f;如果内容有误的话&#xff0c;还望指出&…

Java入门基础学习笔记50——ATM系统

1、项目演示&#xff1b; 2、项目技术实现&#xff1b; 1&#xff09;面向对象编程&#xff1a; 每个账户都是一个对象&#xff0c;所以要设计账户类Account&#xff0c;用于创建账户对象封装账户信息。ATM同样是一个对象&#xff0c;需要设计ATM类&#xff0c;代表ATM管理系…

打破壁垒,实现多引擎3D内容轻量化交付|点量云流

随着应用场景的不断拓展&#xff0c;传统的视频流技术已难以满足日益复杂的需求。当前市场上的视频流解决方案支持的引擎基本是UE、Unitiy输出的exe3D应用&#xff0c;在处理WebGL等3D内容时&#xff0c;也存在诸多局限性&#xff0c;例如性能限制、跨平台兼容性问题、无法直接…

玩转OpenHarmony PID:教你打造两轮平衡车

简介 此次为大家带来的是OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;系统与PID控制算法相结合并落地的平衡车项目。 PID控制算法是一种经典的&#xff0c;并被广泛应用在控制领域的算法。类似于这种&#xff1a;需要将某一个物理量保持稳定的场合&…

java学习五

Java方法 方法是什么 方法Debug 方法定义注意点 方法总结 方法使用时的常见问题