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

这篇具有很好参考价值的文章主要介绍了ZooKeeper是如何保证数据一致性的?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        

目录

一、分布式一致性原理

二、ZooKeeper架构

        2.1 ZAB 协议操作顺序性

        2.2 领导者选举

        成员身份

        成员状态

        领导者选举

三、总结

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

一、分布式一致性原理

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

ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法

        一致性指的是,每次读取的数据都应该是最近写入的数据或者返回一个错误(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),它会将写请求转发给主节点。如图所示:    ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法    

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

ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法

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

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

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

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

        在创建完提案之后,主节点会基于 TCP 协议,并按照顺序将提案广播到其他节点。这样就能保证先发送的消息,会先被收到,保证了消息接收的顺序性。ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法

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

ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法

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

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

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

ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法

        如果客户端必须要读到最新数据,怎么办呢?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 都已经检测到了读操作超时):ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法

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

        一般而言,节点会先接收到自己发送给自己的选票(因为不需要跨节点通讯,传输更快),也就是说,B 会先收到来自 B 的选票,C 会先收到来自 C 的选票:ZooKeeper是如何保证数据一致性的?,ZooKeeper,zookeeper,分布式,ZAB协议,一致性算法

        集群的各节点收到选票后,为了选举出数据最完整的节点,对于每一张接收到选票,节点都需要进行领导者 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博客文章来源地址https://www.toymoban.com/news/detail-847120.html

到了这里,关于ZooKeeper是如何保证数据一致性的?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MySQL和Redis如何保证数据一致性?

    由于缓存的高并发和高性能已经在各种项目中被广泛使用,在读取缓存这方面基本都是一致的,大概都是按照下图的流程进行操作: 但是在更新缓存方面,是更新完数据库再更新缓存还是直接删除缓存呢?又或者是先删除缓存再更新数据库?在这一点上就值得探讨了。 在实

    2024年02月01日
    浏览(51)
  • MySQL和Redis如何保证数据一致性

    MySQL与Redis都是常用的数据存储和缓存系统。为了提高应用程序的性能和可伸缩性,很多应用程序将MySQL和Redis一起使用,其中MySQL作为主要的持久存储,而Redis作为主要的缓存。在这种情况下,应用程序需要确保MySQL和Redis中的数据是同步的,以确保数据的一致性。 “数据一致

    2024年02月12日
    浏览(58)
  • 分布式系统的一致性级别划分及Zookeeper一致性级别分析

    在谈到Zookeeper的一致性是哪种级别的一致性问题,以及CAP原则中的C是哪一种一致性级别时有些疑惑。 下面是大多数文章中提到的一致性级别 一致性(Consistency)是指多副本(Replications)问题中的数据一致性。可以分为强一致性、顺序一致性与弱一致性。 1.1 强一致性(Stric

    2024年04月12日
    浏览(58)
  • 通过zookeeper浅谈一致性算法

    CAP 定理指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。 通俗来说: 一致性(C):当系统数据发生更新操作后,各个主机中的数据仍然处于一致的状态。 可用性(A):对于用户的每一个请求,系统总

    2024年02月07日
    浏览(52)
  • 如何保证ES和数据库的数据一致性?

    在业务中,我们通常需要把数据库中的数据变更同步到ES中,那么如何保证数据库和ES的一致性呢?通常有以下几种做法: 双写 在代码中,对数据库和ES进行双写,并且先操作本地数据库,后操作ES,而且还需要把两个操作放到一个事务中:  在以上逻辑中,如果写数据库成功

    2024年04月28日
    浏览(49)
  • flink如何利用checkpoint保证数据状态一致性

    这本质上是一『尽力而为』的方法。保证数据或事件最多由应用程序中的所有算子处理一次。 这意味着如果数据在被流应用程序完全处理之前发生丢失,则不会进行其他重试或者重新发送。下图中的例子说明了这种情况。 应用程序中的所有算子都保证数据或事件至少被处理

    2024年02月21日
    浏览(48)
  • Redis---数据库和缓存如何保证一致性?

    用「读 + 写」请求的并发的场景来分析: 假如某个用户数据在缓存中不存在,请求 A 读取数据时从数据库中查询到年龄为 20,在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21,并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存

    2024年01月24日
    浏览(52)
  • Redis如何保证缓存和数据库一致性?

    现在我们在面向增删改查开发时,数据库数据量大时或者对响应要求较快,我们就需要用到Redis来拿取数据。 Redis:是一种高性能的内存数据库,它将数据以键值对的形式存储在内存中,具有读写速度快、支持多种数据类型、原子性操作、丰富的特性等优势。 优势: 性能极高

    2024年01月16日
    浏览(66)
  • 如何保证数据库和缓存双写一致性?

    如何保证数据库和缓存双写一致性,是面试中经常被问的一个技术问题,程序汪推荐大家有必要好好研究一波 数据库和缓存(比如:redis)双写数据一致性问题,是一个跟开发语言无关的公共问题。尤其在高并发的场景下,这个问题变得更加严重。 我很负责的告诉大家,该问

    2024年01月18日
    浏览(57)
  • mysql和redis如何保证数据库一致性

    如果对于小公司的单机服务器来说在更新和删除mysql数据的同时对redis缓存进行更新或者删除就行,一般有两个选择,例如: 先更新MySQL,后删除(或更新)Redis 先删除(或更新)Redis,后更新MySQL 但是不管使用其中哪种方式,都存在两个可能的问题: 由于第一步与第二步并不是原

    2023年04月24日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包