ZooKeeper是如何保证数据一致性的?

news2024/11/20 1:32:11

        

目录

一、分布式一致性原理

二、ZooKeeper架构

        2.1 ZAB 协议操作顺序性

        2.2 领导者选举

        成员身份

        成员状态

        领导者选举

三、总结

        在分布式系统里的多台服务器要对数据状态达成一致,其实是一件很有难度和挑战的事情,因为服务器集群环境的软硬件故障随时会发生,多台服务器对一个数据的记录保持一致,需要一些技巧和设计。

一、分布式一致性原理

        关于分布式一致性,相信你肯定听过著名的 CAP 原理。CAP 原理认为,一个提供数据服务的分布式系统无法同时满足数据一致性(Consistency)、可用性(Availibility)、分区容错性(Patition Tolerance)这三个条件,如下图所示。

        一致性指的是,每次读取的数据都应该是最近写入的数据或者返回一个错误(Every read receives the most recent write or an error),而不是过期数据,也就是说,数据是一致的。

        可用性指的是,每次请求都应该得到一个响应,而不是返回一个错误或者失去响应,不过这个响应不需要保证数据是最近写入的(Every request receives a (non-error) response, without the guarantee that it contains the most recent write),也就是说系统需要一直都是可以正常使用的,不会引起调用者的异常,但是并不保证响应的数据是最新的。

        分区容错性指的是,即使因为网络原因,部分服务器节点之间消息丢失或者延迟了,系统依然应该是可以操作的。

        当网络分区失效发生的时候,我们要么取消操作,这样数据就是一致的,但是系统却不可用;要么我们继续写入数据,但是数据的一致性就得不到保证。

        对于一个分布式系统而言,网络失效一定会发生,也就是说,分区容错性是必须要保证的,那么在可用性和一致性上就必须二选一。当网络分区失效,也就是网络不可用的时候,如果选择了一致性,系统就可能返回一个错误码或者干脆超时,即系统不可用。如果选择了可用性,那么系统总是可以返回一个数据,但是并不能保证这个数据是最新的。

        所以,关于CAP原理,更准确的说法是,在分布式系统必须要满足分区耐受性的前提下,可用性和一致性无法同时满足。

二、ZooKeeper架构

        ZooKeeper 主要提供数据的一致性服务,分布式系统共识算法起源于 Paxos 算法。这里假设你已经了解了 Paxos 算法的视线,不了解也没关系,关于 Paxos 算法具体内容请参考往期文章:探索分布式强一致性奥秘:Paxos共识算法的精妙之旅-CSDN博客

        那我们能用 Paxos 来实现 Zookeeper 各节点的数据一致性吗?答案是否定的,Paxos 算法虽然能保证达成共识后的值不再改变,但它不关心达成共识的值是什么,也无法保证各值(也就是操作)的顺序性。而这就是 Zookeeper 没有采用 Paxos 的原因,又是 ZAB 协议着力解决的,也是理解 ZAB 协议的关键。

        首先看下 ZooKeeper 的 ZAB 协议是如何实现操作顺序的?

        2.1 ZAB 协议操作顺序性

        如果用一句话来解释 ZAB 协议到底是什么,应该是:能保证操作顺序性的,基于主备模式的原子广播协议。

        先来看一个例子:假如节点 A、B、C 组成的一个分布式集群,指令(比如 X、Y),我们来看下 ZAB 是如何保证实现顺序性的,假设 A 为主节点,B、C 为备份节点。

        首先,需要注意的是,在 ZAB 中,写操作必须在主节点(比如节点 A)上执行。如果客户端访问的节点是备份节点(比如节点 B),它会将写请求转发给主节点。如图所示:        

        接着,当主节点接收到写请求后,它会基于写请求中的指令(也就是 X,Y),来创建一个提案(Proposal),并使用一个唯一的 ID 来标识这个提案。这里的唯一 ID 就是指事务标识符(Transaction ID,也就是 zxid),如下图。

        从图中可以看到,X、Y 对应的事务标识符分别为 <1, 1> 和 <1, 2>,这两个标识符是什么含义呢?

        可以这么理解,事务标识符是 64 位的 long 型变量,有任期编号 epoch 和计数器 counter 两部分组成(为了形象和方便理解,我把 epoch 翻译成任期编号),格式为高 32 位为任期编号,低 32 位为计数器:

  • 任期编号,就是创建提案时领导者的任期编号,需要注意的是,当新领导者当选时,任期编号递增,计数器被设置为零。比如,前领导者的任期编号为 1,那么新领导者对应的任期编号将为 2。
  • 计数器,就是具体标识提案的整数,需要注意的是,每次领导者创建新的提案时,计数器将递增。比如,前一个提案对应的计数器值为 1,那么新的提案对应的计数器值将为 2。

        为什么要设计的这么复杂呢?因为事务标识符必须按照顺序、唯一标识一个提案,也就是说,事务标识符必须是唯一的、递增的。

        在创建完提案之后,主节点会基于 TCP 协议,并按照顺序将提案广播到其他节点。这样就能保证先发送的消息,会先被收到,保证了消息接收的顺序性。

        然后,当主节点接收到指定提案的“大多数”的确认响应后,该提案将处于提交状态(Committed),主节点会通知备份节点提交该提案。

        需要注意的是,主节点提交提案是有顺序性的。主节点根据事务标识符大小,按照顺序提交提案,如果前一个提案未提交,此时主节点是不会提交后一个提案的。也就是说,指令 X 一定会在指令 Y 之前提交。        

        最后,主节点返回执行成功的响应给节点 B,节点 B 再转发给客户端。你看,这样我们就实现了操作的顺序性,保证了指令 X 一定在指令 Y 之前执行。

        当写操作执行完后,接下来可能需要执行读操作了。需要注意,为了提升读并发能力,Zookeeper 提供的是最终一致性,也就是读操作可以在任何节点上执行,客户端会读到旧数据:        

        如果客户端必须要读到最新数据,怎么办呢?Zookeeper 提供了一个解决办法,那就是 sync 命令。可以在执行读操作前,先执行 sync 命令,这样客户端就能读到最新数据了。

        2.2 领导者选举

        系统在运行中,不可避免会出现各种各样的问题,比如进程崩溃了、服务器死机了,这些问题会导致很严重的后果,让系统没办法运行。在 ZAB 中,写请求是必须在主节点上处理的,而且提案的广播和提交,也是由主节点来完成的。既然主节点那么重要,如果它突然崩溃宕机了,该怎么办呢?答案是选举出新的领导者(也就是新的主节点)。

        成员身份

        既然要选举领导者,那就涉及成员身份变更,那么在 ZAB 中,支持哪些成员身份呢。ZAB 支持 3 种成员身份(领导者、跟随者、观察者)。

  • 领导者(Leader):作为主节点(Primary),在同一时间集群只会有一个领导者,所有的写请求必须在主节点上进行。
  • 跟随者(Follower):作为备份节点(Backup),集群中可以有多个跟随者,它们会响应领导者的心跳,并参与领导者选举和提案提交的投票。跟随者可以直接处理并相应客户端的读请求,但写请求必须转发给领导者。
  • 观察者(Observer):作为备份节点(BackUp),类似跟随者,但是没有投票权,不参与领导者选举和提案提交的投票。

        成员状态

        虽然 ZAB 支持 3 种成员身份,但是它定义了 4 种成员状态。

  • LOOKING:选举状态,该状态下的节点认为当前集群中没有领导者,会发起领导者选举。
  • FOLLOWING :跟随者状态,意味着当前节点是跟随者。
  • LEADING :领导者状态,意味着当前节点是领导者。
  • OBSERVING: 观察者状态,意味着当前节点是观察者。

        为什么多了一种成员状态呢?这是因为 ZAB 支持领导者选举,在选举过程中,涉及了一个过渡状态(也就是选举状态)。

        领导者选举

        为了帮你更好地理解 ZAB 的领导者选举,举个例子演示一下,为了演示方便和更容易理解(我们聚焦最核心的领导者 PK),假设投票信息的格式是 <proposedLeader, proposedEpoch, proposedLastZxid, node>,其中:

  • proposedLeader:领导者的集群 ID,也就是在集群配置(比如 myid 配置文件)时指定的 ID。
  • proposedEpoch:领导者的任期编号。
  • proposedLastZxid:领导者的事务标识符最大值(也就是最新提案的事务标识符)。
  • node:投票的节点,比如节点 B。

        假设一个 ZooKeeper 集群,由节点 A、B、C 组成,其中节点 A 是领导者,节点 B、C 是跟随者(为了方便演示,假设 epoch 分别是 1 和 1,lastZxid 分别是 101 和 102,集群 ID 分别为 2 和 3)。那么如果节点 A 宕机了,会如何选举呢?

        首先,当跟随者检测到连接领导者节点的读操作等待超时了,跟随者会变更节点状态,将自己的节点状态变更成 LOOKING,然后发起领导者选举(假设这时节点 B、C 都已经检测到了读操作超时):

        接着,每个节点会创建一张选票,这张选票是投给自己的,也就是说,节点 B、C 都“自告奋勇”推荐自己为领导者,并创建选票 <2, 1, 101, B> 和 <3, 1, 102, C>,然后各自将选票发送给集群中所有节点,也就是说,B 发送给 B、C,C 也发送给 B、C。

        一般而言,节点会先接收到自己发送给自己的选票(因为不需要跨节点通讯,传输更快),也就是说,B 会先收到来自 B 的选票,C 会先收到来自 C 的选票:

        集群的各节点收到选票后,为了选举出数据最完整的节点,对于每一张接收到选票,节点都需要进行领导者 PK,也就将选票提议的领导者和自己提议的领导者进行比较,找出更适合作为领导者的节点,约定的规则如下: 

  • 优先检查任期编号(Epoch),任期编号大的节点作为领导者;
  • 如果任期编号相同,比较事务标识符的最大值,值大的节点作为领导者;
  • 如果事务标识符的最大值相同,比较集群 ID,集群 ID 大的节点作为领导者。

        如果选票提议的领导者,比自己提议的领导者,更适合作为领导者,那么节点将调整选票内容,推荐选票提议的领导者作为领导者。

        当节点 B、C 接收到的选票后,因为选票提议的领导者与自己提议的领导者相同,所以,领导者 PK 的结果,是不需要调整选票信息,那么节点 B、C,正常接收和保存选票就可以了。

        接着节点 B、C 分别接收到来自对方的选票,比如 B 接收到来自 C 的选票,C 接收到来自 B 的选票。对于 C 而言,它提议的领导者是 C,而选票(<2, 1, 101, B>)提议的领导者是 B,因为节点 C 的任期编号与节点 B 相同,但节点 C 的事务标识符的最大值比节点 B 的大,那么,按照约定的规则,相比节点 B,节点 C 更适合作为领导者,也就是说,节点 C 不需要调整选票信息,正常接收和保存选票就可以了。

        接着,当节点 B、C 接收到来自节点 B,新的选票时,因为这张选票(<3, 1, 102, B>)提议的领导者,与他们提议的领导者是一样的,都是节点 C,所以,他们正常接收和存储这张选票,就可以。

        最后,因为此时节点 B、C 提议的领导者(节点 C)赢得大多数选票了(2 张选票),那么,节点 B、C 将根据投票结果,变更节点状态,并退出选举。比如,因为当选的领导者是节点 C,那么节点 B 将变更状态为 FOLLOWING,并退出选举,而节点 C 将变更状态为 LEADING,并退出选举。

        到此,领导者选举结束。

三、总结

        总之,ZAB 协议是 ZooKeeper 实现其作为分布式协调服务核心功能的关键所在,确保了在复杂网络环境和机器故障情况下,仍能提供强大而一致的数据服务,支撑起众多分布式系统的协同工作。

往期经典推荐

探索分布式强一致性奥秘:Paxos共识算法的精妙之旅-CSDN博客

Raft共识算法领导者选举流程揭秘-CSDN博客

Redis使用规范的最佳实践:打造高性能与稳定性的关键法则-CSDN博客

SpringBoot项目并发处理大揭秘,你知道它到底能应对多少请求洪峰?_springboot并发处理-CSDN博客

Kafka消息流转的挑战与对策:消息丢失与重复消费问题_kafka发送消息生产者关闭了-CSDN博客

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

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

相关文章

信息学奥赛一本通之MAC端VSCode C++环境配置

前提 安装 Visual Studio CodeVSCode 中安装 C/C扩展确保 Clang 已经安装&#xff08;在终端中输入命令&#xff1a;clang --version 来确认是否安装&#xff09;未安装&#xff0c;在命令行执行xcode-select --install 命令&#xff0c;会自行安装&#xff0c;安装文件有点大…

ENVI实战—地物波谱分类

实验1&#xff1a;浏览内置波谱库 目的&#xff1a;学会使用波谱浏览器&#xff0c;浏览内置波谱库&#xff0c;以进行课程后继实验 过程&#xff1a; ①打开ENVI软件&#xff0c;在窗口选择“显示”并点击&#xff0c;找到“波谱库浏览器”并打开&#xff0c;此时可以浏览ENVI…

天童美语开学季|开启“热辣滚烫”的新学期

新学期伊始&#xff0c;孩子们即将踏入一个充满挑战和机遇的学习环境。在这个关键时刻&#xff0c;学校和家庭需要更加紧密地协调合作&#xff0c;以确保孩子们能够得到充分的支持和帮助&#xff0c;顺利成长。    在假期生活分享中开启新学期第一课      寒假里孩子们…

聚观早报 | 追觅科技亮相AWE2024;三星家电举办发布会

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 3月18日消息 追觅科技亮相AWE2024 三星家电举办发布会 深蓝汽车将采用华为HI模式 字节跳动2023年全球营收 特斯…

光伏便携式EL检测仪是什么?—科技助农

光伏便携式EL监测仪是一种专门用于检测光伏电池组件性能的高效、实用的设备。它利用电致发光&#xff08;Electroluminescence&#xff0c;EL&#xff09;原理&#xff0c;通过检测光伏板在受到光照后产生的电流所激发出的光线&#xff0c;来评估光伏板的性能。这种设备通常具有…

兰宝传感授权世强硬创代理全线产品,提高工业智能传感器市场渗透率

智能传感器作为工业物联、智能制造的关键核心部件&#xff0c;国产化进程下&#xff0c;当前国内市场对智能传感器的替代需求已从中低端产品延伸至高端产品&#xff0c;上游企业的产品也随之迭代更新。 为满足市场对高端智能传感器的多样化需求&#xff0c;世强先进&#xff0…

Armv8状态寄存器

Processor state AArch64没有与ARMv7当前程序状态寄存器直接对应的寄存器(CPSR)。在AArch64中&#xff0c;传统CPSR的组件以字段的形式提供可独立访问。这些统称为处理器状态(PSTATE)。 在AArch64中&#xff0c;通过执行ERET指令从异常中返回&#xff0c;这会导致要拷贝到PSTAT…

《手把手教你》系列技巧篇(四十)-java+ selenium自动化测试-JavaScript的调用执行-下篇(详解教程)

1.简介 在实际工作中&#xff0c;我们需要对处理的元素进行高亮显示&#xff0c;或者有时候为了看清楚做跟踪鼠标点击了哪些元素需要标记出来。今天宏哥就在这里把这种测试场景讲解和分享一下。 2.用法 创建一个执行 JS 的对象&#xff0c;也就是 JavascriptExecutor 对象&…

Flutter生命周期方法小技巧

需求 A界面跳转到B界面,暂停A界面的音乐或者视频B界面返回到A界面&#xff0c;播放A界面的音乐或者视频A界面切换到后台&#xff0c;暂停A界面的音乐或者视频A界面从后台切换到前台,播放A界面的音乐或者视频 需求通过理解修改为&#xff1a; 监听 StatefulWidget 的 onPause…

基于高斯模型的运动目标检测(车辆检测),Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

机器学习 --- 模型评估、选择与验证

Java实训代码、答案&#xff0c;如果能够帮到您&#xff0c;希望可以点个赞&#xff01;&#xff01;&#xff01; 如果有问题可以csdn私聊或评论&#xff01;&#xff01;&#xff01;感谢您的支持 第1关&#xff1a;为什么要有训练集与测试集 1、下面正确的是&#xff1f;&…

(每日持续更新)jdk api之StringReader基础、应用、实战

博主18年的互联网软件开发经验&#xff0c;从一名程序员小白逐步成为了一名架构师&#xff0c;我想通过平台将经验分享给大家&#xff0c;因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验&#xff0c;晚上进行用心精简、整理、总结、定稿&…

LeetCode 面试经典150题 121.买卖股票的最佳时机

题目&#xff1a; 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易…

数学建模——蒙特卡洛法

目录 1.介绍2.可以做的题型3.实战3.1求pi的值3.2求定积分x^2 的值 参加了大大小小很多场比赛了&#xff0c;但是都是混子&#xff0c;但还是打算记录一下吧&#xff0c;系统认真过一遍。后续功力深厚&#xff0c;会拓展写的文章&#xff0c;目前是干货&#xff0c;一些背景啥的…

蓝桥杯刷题(十)

1.翻转 代码 输入数据&#xff0c;每组数据进行比较&#xff0c;j的范围掐头去尾&#xff0c;若a[j]b[j]&#xff0c;继续&#xff0c;若出现010,101子串则改成000,111&#xff0c;遍历完后比较a是否等于b&#xff0c;相同则输出次数&#xff0c;不同则输出-1。 for _ in ran…

CSS概念及入门

文章目录 1. CSS 概念及入门1.1. 简介1.2. 组成1.2.1. 选择器1.2.2. 属性 1.3. 区别 2. CSS 引入方式2.1. 行内样式2.1.1. 语法2.1.2. 特点 2.2. 内部样式2.2.1. 语法2.2.2. 特点 2.3. 外部样式2.3.1. 特点 2.4. 三种引入优先级 1. CSS 概念及入门 1.1. 简介 CSS 的全称为&am…

打破传统,拥抱未来:解锁企业数字化转型成功的11把金钥匙

数字化转型是一个持续的过程&#xff0c;需要企业不断地适应新技术和市场变化。企业如何提高转型成功的可能性&#xff0c;并在竞争激烈的市场中保持领先地位。今天我们来解锁企业数字化转型成功的11把金钥匙。 清晰的战略目标&#xff1a; 首先&#xff0c;企业需要明确数字化…

Python基础(八)之流程控制

Python基础&#xff08;八&#xff09;之流程控制 Python控制流程分为三种接口&#xff1a; 顺序结构选择结构循环结构 1、顺序结构 程序代码自上而下运行&#xff0c;逐条执行每一条Python代码&#xff0c;不重复执行任何代码&#xff0c;也不会跳过任何代码。 当语句与语…

基于JavaWeb+SSM+Vue“鼻护灵”微信小程序系统的设计和实现

基于JavaWebSSMVue“鼻护灵”微信小程序系统的设计和实现 滑到文末获取源码Lun文目录前言主要技术系统设计功能截图 滑到文末获取源码 Lun文目录 摘 要 3 Abstract 1 1 绪 论 1 1.1研究背景 1 工作的效率。 1 1.2 研究意义 1 1.3研究现状 1 1.4本文组织结构 2 2 技术介绍 3 2…

揭秘Facebook:数字世界的引领者

在当今数字化社会中&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;扮演着引领者的角色。它不仅改变了人们的社交方式&#xff0c;还深刻影响着信息传播、商业模式和社会责任。本文将深入揭秘Facebook背后的故事&#xff0c;探索其在数字世界中的引领地位和影…