画图说透 ZooKeeper如何保证数据一致性:选举和ZAB协议

news2024/12/23 0:45:40

1、zookeeper是什么?

zookeeper能被各个牛逼的中间件项目中所依赖,已经说明了他的地位。一出手就是稳定的杀招。zookeeper是什么?官网中所说,zookeeper致力于开发和维护成为一个高度可靠的分布式协调器。

开局一张图,官网就是酷,(图片来自官网)。

zookeeper能干的事情很多:

分布式锁】,zookeeper特殊的数据结构和watcher机制,让他也能高效的实现分布式锁的功能,参考Curactor这款框架,分布式锁开箱即用。

元数据管理】,Kafka就是使用zookeeper存储核心元数据。

分布式协调】,zookeeper的watcher机制可以让分布式系统中的各个节点监听某个数据的变化,并且zookeeper可以把数据变化反向推送给订阅了的节点,例如kafka里面的各个broker和controller之间的协调。

Master选举】,HDFS就是用了zookeeper来保证Namenode的 HA高可用,可以保证只有一台成为主。

zookeeper提供了全方位的分布式场景下丰富的功能,分布式协调的王者不是虚名。

zookeeper一般是集群部署,单机不可能满足上面提到的这些功能的实现。我们一般都是用3-5台机器。每台机器都会在内存存储所有的元数据。划重点,zookeeper是基于内存存储的,这已经决定了他能实现高吞吐高性能。

zookeeper的内存数据结构,就像linux系统的文件系统,是一种树形结构,每个节点我们叫做znode。zookeeper的节点大致分为三种类别,一个是临时节点,一个是持久节点,还有顺序节点。灵活运用,组合这些节点,我们在实际开发中能实现各种神奇的功能。

2.zookeeper的架构?

既然是分布式领域的一个王者,zookeeper具备哪些特性才让他立足呢?

  1. 集群部署,首先部署上肯定是集群部署,单机肯不靠谱的。
  2. 高可用,必须要保证高可用,一旦集群中的某台机器宕机,不能导致数据丢失
  3. 原子性,既然zookeeper走的CP,那么一定要保证每次数据写入,集群中所有机器必须要要么全部成功,要么就全部写入失败。
  4. 数据一致性,同(3)理,数据一致性也要保证,无论我客户端连接那一台机器,我get某个数据一定是一致的
  5. 顺序性,zookeeper的写入,实现了有序的写入,这也夯实了自己数据一致性的特性。
  6. 实时感知,zookeeper的watcher机制无疑是一个强大的功能,一旦某个数据发生变化,感知要实时,不然就失去意义了。
  7. 高性能,无论是做什么样的功能,超高的读写性能才是根本,zookeeper的数据是存储在内存中的,这本身就带来了超高的性能。并且同时也能带来超高的并发能力

要做到这些,架构设计上是绝对有很多亮点的,我们来看看zookeeper的架构设计。

首先我们先来认识一下zookeeper中的几个角色:

  • leader,集群启动,一定会选择一个节点作为主节点。一个集群中只有一个主节点,并且只有主节点接收并处理写请求。

  • follower,从节点,首先从节点是不能处理写请求的,就算某个客户端连接到从节点提交写请求,最终也是转发到主节点leader处理。从节点只负责读请求。

    当leader宕机的时候,并且当前集群中宕机的数量不超过一半,那么集群会重新发起选举,从follower中选举出新的leader。

  • Observer,顾名思义,观察者,一般我们接触zookeeper貌似都不怎么用到它,也注意不到他,如果你希望你的读并发能力能抗更多的请求,你可以选择挂载Observer。它只提供数据读取的服务。

当客户端和zookeeper建立起连接,是基于TCP的长连接,一个会话session,通过心跳机制,感知是否断开,如果断开,只要在sessionTimeout时间内重新连接,就能保持住长连接。

zookeeper的数据结构是znode树型结构,如上文一样,我们每次写入就是构建树节点下的叶子结点。并且创建的节点分为持久节点和临时节点。

  • 持久节点一旦创建,会持久化到磁盘,哪怕客户端断开,下次依然可以读取到。
  • 临时节点则不一样,一旦客户端断开连接的话就不存在了。和持久节点和临时节点能够组合的还有是否有序,在zookeeper的客户端curactor框架中就是基于临时顺序节点实现了分布式锁。

znode的结构长什么样呢?我们执行一次get操作,可以得到如下这样子的数据结构。

上文说过zookeeper一个很重要的功能是分布式协调,这就要依赖于zookeeper的监听回调机制,watcher机制,当客户端监听一个节点,当节点发生变化的时候反向通知客户端,如此便可以实现对订阅数据变化的感知,并做出响应的处理。基于TCP,天然可以实现这样的功能。

3.ZAB是什么?

Zookeeper一般都是集群部署,那么集群之间各个节点是如何同步数据的呢?如何才能保证数据对外的一致性呢?

这里就引出了Zookeeper的自己参照一致性协议paxos实现的,独有的ZAB协议,zookeeper Atomic Broadcastzookeeper原子广播协议。正是通过这个协议,zookeeper的集群之间进行数据同步,保证数据的强一致性。

首先我们来拍脑袋想一想哪些情况下数据会不一致呢?正如上文提到的,所有的写请求是转发给leader处理的,再加上同步给follower,这中间网络通信,会出现各种情况,甚至leader崩溃,follower崩溃,这些都会导致数据不一致。

那么ZAB协议是怎么起到保证一致性的作用呢?

  1. 首先明确的是整个zookeeper集群中的几个角色划分,只有leader负责写入数据,follower只负责从follower同步数据已经对外提供读取数据。可以说zookeeper实现的就是主备模型

    我们可以认为,一次写入就是一次分布式事务,从写入请求到leader,到follower的数据同步,到写入成功,返回客户端ACK。这就是分布式事务嘛。

  2. 当leader收到一条写入请求,这里我们称之为一次事务请求,就会将客户端事务请求转换成事务Proposal(提议,提案),并且将这个事务Proposal发送给所有的Follower节点,也就是向所有的follower节点发送数据广播请求。

  3. 广播事务Proposal之后leader就要等待所有的Follower服务器的返回,(ack请求),划重点,在ZAB协议中明确了只要有超过半数的Follower节点正确的返回了ACK,就认为本次提案是successful的。那么此时leader就会向所有的Follower服务器广播commit消息,对前一次的事务Proposal发起提交。这里我们敏锐的可以感觉到,脑海里浮现了一个词语 2PC。这个后面再说。

  4. 上面的过程我们可以理解为是一个2PC的过程,并且需要过半的机器成功接收到事务Proposal,并返回ACK,也就是过半写,2PC+过半写,这是ZAB协议的一个核心点。

我们再想想leader从哪里的呢?上面讨论的所有问题都是在唯一一台leader存在的情况下,那么leader是如何产生的?leader宕机了又该怎么办?这个是我们接下来要一点点分析的问题。

4.从启动到崩溃,ZAB协议做了什么?

我们来讨论leader从哪里来?既然是最有权势的一个leader,没有规矩,谁都能当?那肯定集群里面的节点都争着要当的,这时候我们就要自然是要选举出来的。怎么选,这也是ZAB协议里有规定的。

当一个ZK集群启动的时候,会进入崩溃恢复模式,直到选举出一个leader,并且只要过半的Follower机器都和leader机器同步完数据,就会退出崩溃恢复模式,对外提供服务,此时就进入了消息广播模式。

崩溃恢复模式消息广播模式是zookeeper集群工作的主要俩个模式。

我们接着说leader选举的事情,ZAB协议规定leader选举只要过半的机器都投票给某一台机器,这台机器就成为leader,这里自己也可以投票给自

己。如果leader突然宕机了,此时整个集群再次进入崩溃恢复模式,重新选举新的leader。

消息广播模式就是集群数据副本传递的主要的策略,上文我们也说到了2PC,但其实zookeeper还是为了性能做了优化,并不是要所有的follower都

返回ACK,只要过半数返回ACK就认为本次事务Proposal是写入成功的,就可以发起commit请求了。

这里我们其实是有疑惑的,这样子,zookeeper还是强一致性么?毕竟在某个时间点,也不是所有的机器都拥有一致的副本啊,这么看来也不能说

Zookeeper是实现了强一致性的CP模型,这里有个结论,最终所有的机器会实现数据副本一致性

消息广播模式下,每次从客户端有一个事务请求过来,leader会转化为事务Proposal,并且写入本地磁盘,还会给每个事务Proposal分配一个全局

唯一的Zxid。

还有个细节,当leader向所有的Follower发起事务Proposal时,不是就随随便便发送的,leader为每一个Follower都维护了一个先进先出的队

列,每一个事务Proposal都是按照顺序依次放入,保证有序性。当Follower接收到事务Proposal时,会将其写入本地磁盘。

这里还有异步解耦的功效,也一定程度上提高了事务Proposal的广播速度。那么这里我们还可以说zookeeper实现的是顺序一致性,这样看起来,更大程度的保证了数据的一致性。

5.Zxid的组成

Zxid其实就是事务id,为了保证事务的顺序一致性,zookeeper 采用了递增的事务id(Zxid)来标识事务。所有的提案(proposal)都在被提出的时候加上了 Zxid

Zxid是64位的数字,高32位是任期编号,低32位是事务计数器:

image-20230303105046002

  • 图中高32位:epoch,ZAB协议通过epoch 编号来区分 Leader 周期变化,用来标识 leader 关系是否改变,每次新 leader 被选出来,所有节点的新epoch值为:(epoch初始值=1):new epoch值=old epoch值+1

可以理解成,标识当前集群属于哪个leader的统治时期,保证了即使旧leader恢复后也没有人再从属于它(数据同步后就成了follower),因为 follower 只听从当前epoch的 leader 的命令。

  • 图中低32位transactionCount:用于递增计数,每接收到一条写入请求,这个值+1。新 leader选举后这个值重置为0。

这样设计的好处在于老的leader挂了以后重启,它不会被选举为 leader,因此此时它的 zxid 肯定小于当前新的 leader。当老的 leader 作为follower 接入新的leader 后,新的leader会让它将所有的拥有旧的 epoch号并且未被COMMITproposal 清除掉。

6.数据不一致了,ZAB协议的策略

以上大概描述了ZAB协议下,zk集群中leader和follower之间数据副本的同步过程,我们在这里稍微消耗脑细胞地想一下,有没有什么情况,会导致数据不一致?

  1. 当一个客户端发过来的事务写请求,刚刚被leader写到本地,还没来得及发起Proposal就宕机了,这时候会数据不一致么? 【P1】
  2. 如果一个事务Proposal写入是成功的,并且广播给所有的Follower机器,也受到了过半机器的ACK,此时leader节点挂了,并且此时可能leader已经本地commit了,那么新的leader选举出来之后,这台老的leader重新启动了之后,数据会不一致么? 【P2】

细细一想,不经冷汗,这些也是问题啊,ZAB要保证自己说到的一致性就必须要解决这俩种情况,如何解决呢?

关键就在于新leader的选举算法,要保证2点:

  1. ZAB协议必须保证恢复处理后 【P2】 的需要在所有服务器上都提交成功
  2. ZAB必须将恢复后(此时已经有新leader了,已经跳过 【P1】 )重新注册的老leader机器所在的日志中删除掉 【P1】

上文所说的每个事务Proposal分配一个全局唯一的Zxid,并且是递增的。再加上任期的概念,一切又开始向着一致性的方向迈进了。

如果 leader 选举算法能够保证新选举出来的 leader服务器拥有集群中所有机器最高编号(【Zxid最大】)的事务 Proposal,那么就可以

保证这个新选举出来的 Leader 一定具有已经提交的提案。

毕竟所有提案被COMMIT之前必须有超过半数的 follower ACK,即必须有超过半数节点的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保 存了所有被 COMMIT 消息的 proposal 状态。而这个节点肯定会拥有最大的Zxid

综上:

ZooKeeper主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性

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

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

相关文章

STM32MP157-Linux音频应用编程-简易语音助手

文章目录前言STM32MP157简易语音助手alsa-lib简介:移植alsa-lib库:libcurl库简介:移植libcurl库:API调用修改asrmain.c文件修改token.c文件录音文件IO打开音频文件硬件控制sysfs文件系统数据解析和控制多线程主循环实现效果及注意…

Hive与HBase的区别及应用场景

当数据量达到一定量级的时候,存储和统计计算查询都会遇到问题,今天了解一下Hive和Hbase的区别和应用场景。 一、定义 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能&am…

Umi使用百度地图服务

需求描述 需要在前端页面中使用地图定位功能,所以在前端umi项目中使用百度地图服务,由于umi项目默认没有入口的html文件,所以无法通过常规的在head中加入外链js的方式使用 百度ak zyqeLCzvQPCCNImRu9yRGOqWlEUicxxGreact使用百度api 链接:…

【Mybatis系列】Mybatis常见的分页方法以及源码理解

Mybatis-Plus的selectPage 引入依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency>添加分页插件 Configuration public class My…

ifm3dlib+Python实现摄像头点云数据保存

0. 起因&需求 现有一款摄像头 O3D303&#xff0c;通过网线将其连接到局域网后&#xff0c;同一局域网的电脑可以通过可视化软件查看到各项参数以及对应的点云图。 但是如果想定制化具体的需求&#xff0c;用官方的可视化软件无疑是不可取的。这时候就需要用到SDK&#xf…

【Java】JVM

一、介绍 1.什么是JVM? JVM是一种用于计算设备的规范&#xff0c;它是一个虚构出来的机器&#xff0c;是通过在实际的计算机上仿真模拟各种功能实现的。JVM包含一套字节码指令集&#xff0c;一组寄存器&#xff0c;一个栈&#xff0c;一个垃圾回收堆和一个存储方法域。JVM屏…

面向对象设计模式:创建型模式之抽象工厂模式

一、抽象工厂模式&#xff0c;Abstract Factory Pattern 1.1 Definition 定义 抽象工厂模式是围绕一个抽象工厂&#xff08;其他工厂的工厂&#xff09;创建其他工厂的创建型模式。 1.2 Intent 意图 Provide an interface for creating families of related or dependent o…

【AutoSAR】【MCAL】Dio

一、结构 二、功能介绍 DIO&#xff08;数字输入输出&#xff09;驱动模块主要是对端口&#xff08;Port&#xff09;&#xff0c;通道&#xff08;Channel&#xff09;和通道组&#xff08;ChannelGroup&#xff09;进行读写操作。 通道&#xff08;Channel&#xff09;&…

Tomcat服务器配置以及问题解决方案

文章目录01 Tomcat简介02 Tomcat的安装03 Tomcat的使用启动Tomcat服务器 &#xff08;解决一闪而过&#xff09;测试 Tomcat 是否启动Tomcat 服务器的关闭04 Tomcat的配置配置端口控制台配置&#xff08;乱码解决&#xff09;部署工程到Tomcat中01 Tomcat简介 Tomcat是一款开源…

Android Compose——一个简单的Bilibili APP

Bilibili移动端APP简介依赖效果登录效果WebView自定义TobRow的Indicator大小首页推荐LazyGridView使用Paging3热门排行榜搜索模糊搜索富文本搜索结果视频详情合集信息Coroutines进行网络请求管理&#xff0c;避免回调地狱添加suspendwithContextGit项目链接末简介 此Demo采用A…

Motor-DK (MM32SPIN05PF, MM32SPIN06PF, MM32SPIN07PF)

输入电压范围&#xff1a;12V - 30V 使用 60V / 40A N-MOS 管 使用内建&#xff08;MM32SPIN2x&#xff09;/外挂&#xff08;MM32SPIN05 / MM32SPIN06 / MM32SPIN07&#xff09;GBW 6MHz 高速运放 x 4 MCU 使用 5V 供电 支持 48 / 64 Pin MM32SPIN 系列 MCU 支持无霍尔&#x…

LearnDash测验报告如何帮助改进您的课程

某一个场景。Pennywell 大学有一门课程“Introduction to Linear Algebra”。上学期进行了两次测验。20% 的学生在第一次测验中不及格&#xff0c;而 80% 在第二次测验中不及格。在进一步评估中&#xff0c;观察到第一次测验不及格的学生在第二次测验中也不及格。在第二次测验中…

基于Linux系统-搭建Java Web开发环境

目录 1. 安装JDK 2.安装MySQL数据库 3.安装Tomcat 4.访问Tomcat 1. 安装JDK 1.执行以下命令&#xff0c;查看yum源中JDK版本。 yum list java* 2.执行以下命令&#xff0c;使用yum安装JDK1.8。 yum -y install java-1.8.0-openjdk* 3.执行以下命令&#xff0c;查看是否安…

【软件使用】MarkText下载安装与汉化设置 (markdown快捷键收藏)

一、安装与汉化 对版本没要求的可以直接选择 3、免安装的汉化包 1、下载安装MarkText MaxText win64 https://github.com/marktext/marktext/releases/download/v0.17.1/marktext-setup.exe 使用迅雷可以快速下载 2. 配置中文语言包 中文包下载地址&#xff1a;GitHub - chi…

TPU编程竞赛系列|算能赛道冠军SO-FAST团队获第十届CCF BDCI总决赛特等奖!

近日&#xff0c;第十届中国计算机学会&#xff08;CCF&#xff09;大数据与计算智能大赛总决赛暨颁奖典礼在苏州顺利落幕&#xff0c;算能赛道的冠军队伍SO-FAST从2万余支队伍中脱颖而出&#xff0c;获得了所有赛道综合评比特等奖&#xff01; 本届CCF大赛吸引了来自全国的2万…

【MySQL】查询访问方法

查询语句经过查询优化器生成 SQL 执行计划&#xff0c;在引入索引的情况下&#xff0c;MySQL 不可能让我们什么查询都是走全表扫描&#xff0c;那样效率太低了&#xff0c;所有需要有各种各样的执行计划 &#xff0c; MySQL 会根据经验为我们的查询语句生成它认为最优的执行计划…

mac安装nvm

1、nvm介绍 &#xff08;1&#xff09;什么是nvm&#xff1f;简单来说&#xff0c;nvm是一款可以用命令行快速切换node版本的工具&#xff01; &#xff08;2&#xff09;为什么要切换node版本&#xff1f;打个比方&#xff0c;你目前正在用node 14版本&#xff0c;现在出了nod…

Greenplum-主备同步机制

我们在学习Greenplum的架构时知道&#xff0c;Greenplum中主要有Master管理层和Segment计算层。在高可用方面&#xff0c;Master通过配置一个Standby来实现主备&#xff0c;Segment则通过对实例设置镜像的方式也实现主备高可用&#xff08;其中主实例称为Primary&#xff0c;备…

网络基础(二)

目录 应用层 再谈 "协议" 协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢? 为什么要转换呢&#xff1f; 如果我们将struct message里面…

传输线的物理基础(二):信号在传输线中的速度

铜中电子的速度信号在传输线上传输的速度有多快&#xff1f;如果人们经常错误地认为信号在传输线上的速度取决于导线中电子的速度。凭着这种错误的直觉&#xff0c;我们可能会想象降低互连的电阻会提高信号的速度。事实上&#xff0c;典型铜线中电子的速度实际上比信号速度慢约…