【Java核心能力】一篇文章了解 ZooKeeper 底层运行原理

news2024/9/25 1:19:11

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

一篇文章了解 ZooKeeper 底层运行原理

该文章主要说一下 ZooKeeper 底层运行原理,以及其中比较核心的功能

CAP 是分布式系统中的基本理论,一般只能满足 AP 和 CP,常用的注册中心 ZK 和 Nacos:

  • ZooKeeper 符合 CP选择了一致性而抛弃了部分可用性 ,因为 ZK 集群中只有 Leader 节点可以写数据,如果 Leader 挂了,需要重新选举 Leader,在这期间 ZK 集群不可用,ZK 只有 Leader 可以写,所以整个写入操作是 中心化
  • Nacos 符合 AP选择了可用性并且满足最终一致性 ,并且 Nacos 的设计是去中心化的

并且由于 ZK 的监听机制,导致在节点数量较多的时候,如果出现大量监听事件的触发,会导致 ZK 瞬时流量过大 ,因此,现在将 Zookeeper 作为服务注册中心的公司在减少,而是转向使用 Nacos 或自研注册中心

首先说一下 ZooKeeper 用来做什么

ZooKeeper 是一个分布式协调服务,提供了一个中心化的服务,用于管理和协调分布式应用中的各种配置、信息和事件

那么一般使用 ZooKeeper 中,较常用的场景就是 注册中心元数据管理

元数据管理 指对多个分布式服务中都需要用到的基础类型的数据进行管理,使用 ZK 管理的好处就是不需要在每一个分布式服务中都进行配置,只要在 ZK 中进行配置即可,并且配置变更之后,所有的分布式服务可以及时收到 数据变更的通知

注册中心 指在那些需要进行 RPC 远程调用时,将 RPC 服务注册到 ZK 中去,之后需要调用的话,可以在 ZK 中查询提供了哪些服务可以进行调用,并且可以进行 负载均衡 处理

如下图,如果提供了一个 HelloServiceImpl 的 RPC 服务,将该服务注册在 ZK 中,节点值为该服务的 IP 地址,这样调用方在需要使用服务的时候,可以拿到该服务的 IP 地址,与该服务建立 TCP 连接即可进行通信(Dubbo 的注册中心可以使用 ZK 也可以使用 Nacos)

image-20240328122134775

ZooKeeper 中的核心内容

ZooKeeper 中的核心内容如下:

  • 节点类型
  • watcher 监听机制
  • 分布式锁
  • 集群模式

接下来主要从这几块内容来介绍 ZooKeeper 的运行原理

节点类型

ZK 中的节点类型分为:持久节点、临时节点、顺序节点

持久节点:创建之后一直存在

临时节点:只要客户端断开连接,节点就会被删除

顺序节点:创建节点时,会添加全局递增的序号,经典应用场景是 分布式锁 (顺序节点既可以是持久节点也可以是临时节点)

节点使用应用场景: 在 RPC 调用中,将提供的 RPC 服务作为临时节点注册在 ZK 中,当 RPC 服务提供者与 ZK 断开连接之后,该服务在 ZK 中注册的临时节点就会被删除,那么我们客户端就可以对该节点添加监听器,当发现节点被删除之后,就可以感知到对应的服务下线了(监听器的内容会在后边说道)

ZooKeeper 的监听机制

ZooKeeper 提供了 watcher 监听机制,这是 ZK 中最常用的功能,因为多个分布式节点之间及时感知到 ZK 数据的变化就是通过 监听机制实现的

ZK 中的 watcher 有以下几个特点:

  • 一次性: watcher 被触发之后,ZK会将其从客户端的 WatchManager 中删除,也会从服务端删除,重新注册 watcher 才可以继续下一次的监听
  • 串行性: 同一 Node 的相同事件类型引发的 watcher 回调方法串行执行(也就是只有执行完w atcher 的回调,才可以重新生成 watcher 对象进行监听,如果回调执行时间太长,可能会导致监听事件的丢失,因此 ZK 也不适合在 watcher 回调中执行耗时的IO操作)

上边说的 watcher 监听是 ZK 中原生的监听机制,我们使用 ZK 都是使用它的客户端工具 Curator,该客户端工具中也封装了一些丰富的功能来提供给我们进行使用,如 分布式锁节点监听机制

这里说一下 Curator 提供的节点监听机制 ,提供了有 3 种类型的监听:

  • NodeCache :监听指定节点(单个节点监听)
  • PathChilrenCache :监听指定节点的子节点
  • TreeCache :监听指定节点

那么对于 监听机制的使用 ,这里还是以 RPC 远程服务调用为例,如果每一个 RPC 服务提供者都会将自己的 IP 地址注册到对应的节点下,那么客户端只需要对 com.zqy.service.impl.HelloServiceImpl 这个节点下的子节点进行监听,就可以感知到哪些服务已经下线,就不再对该服务进行远程调用即可,那么这里就可以使用 PathChildrenCache 来进行监听(具体的代码示例这里就不写了,只讲原理)

image-20240328122134775

分布式锁

ZK 作为分布式协调框架,用来作为分布式锁使用从他的设计目的上来讲是比较合适的,那么常用的分布式锁还有 Redis 的分布式锁(Redisson 客户端框架提供)

  • 对于这两种锁到底要如何去选择使用呢?

其实使用哪一种都可以,两者提供的分布式锁功能都可以满足日常的使用,并且使用 Redis 集群和使用 ZK 集群都可以保证较好的锁的可用性

但是两者在 极端情况下也会出现问题 ,如在 Redis 集群加锁,写入主节点之后,如果锁的信息未来得及同步到从节点,此时主节点宕机,就会导致这个锁的信息丢失,会出现 重复加锁 的情况;在 ZK 集群中,如果客户端长时间 GC 导致无法与 ZK 维持心跳,ZK 会误认为该客户端下线,将该客户端加锁的临时节点删除,也会出现 重复加锁 的情况

那么可以看到在 功能性可用性 上,两者其实差别都不大,具体选用的话,可以 根据当前项目使用的技术栈 来进行选择,比如当前项目中并没有引入 Redis 依赖,只有 ZK 依赖,那么直接使用 ZK 的分布式锁,完全没有必要去引入 Redis 集群来使用 Redis 的分布式锁,因为多一种技术,就多一份故障的风险,单单为了使用 Redis 分布式锁就去引入 Redis 集群显然小题大做了

  • ZK 中的分布式锁实现

ZK 的分布式锁就是依靠 临时顺序节点 实现的,比如说创建一把名为 lock 的锁,那么所有需要加锁的客户端会到该节点下创建 临时顺序节点 ,只有第一个创建成功的客户端可以拿到锁,其他客户端创建的临时顺序节点在后边排序,并且对前一个节点进行 监听 ,当监听到锁释放,自己就拿到了锁(可以了解一下 Curator 对读写锁出现的羊群效应的解决)

image-20240328132722256

ZooKeeper 集群

接下来说一下 ZK 的集群部署,ZK 集群中通过分布式一致性协议 ZAB 来保证数据同步的一致性,以及 Leader 选举、集群的崩溃恢复,接下来会主要 围绕 ZAB 协议 来说一下 ZK 集群相关的核心内容:

ZK 集群中有三种角色:Leader、Follower、Observer

  • Leader :执行写操作,并且向 Follower 进行同步
  • Follower :从 Leader 同步数据,执行读操作,不可以执行写操作
  • Observer :只可以执行读操作

ZK 集群其实是适合 写少读多 场景的,因为整个集群只有 1 个 Leader 可以写,其他节点只可以读,那么你可能有疑问,Follower 节点用来读数据,为什么还需要 Observer 节点呢?

这是因为在集群中 Leader 完成写请求是需要经过半数以上的 Follower 都 Ack 之后,才可以成功写入的,如果集群中 Follower 过多,会大大增加 Leader 节点等待 Follower 节点发送 Ack 的时间,导致 ZK 集群性能很差,因此 ZK 集群部署都是 小集群部署 ,一般都是 3 台或者 5 台机器

Observer 节点Observer 是只读的、不参与 Leader 选举、也不参与 ZAB 协议同步时过半 Ack 的环节,只是单纯的接收数据,同步数据,达到数据顺序一致性的效果,当读并发请求过高时,可以 通过不断添加 Observer 节点来分散读请求的压力

  • ZK 的分布式一致性协议 ZAB 保证数据同步的一致性

ZAB 协议中是采用 2PC 两阶段提交思想完成数据写入的:

采用 2PC 两阶段提交思想 的 ZAB 消息广播流程:

每一个消息广播的时候,都是基于 2PC 的思想,先是发起事务提议 Proposal 的广播,各个 Follower 返回 Ack,当过半的 Follower 都返回 Ack 之后,Leader 就发送 Commit 消息到 Follower,让大家提交事务

这里的两阶段指的就是发送 ProposalCommit

发起一个事务 Proposal 之前,Leader 会分配一个全局唯一递增的事务 id(zxid),以此来严格保证顺序

Leader 会为每个 Follower 创建一个队列,里边存放要发给 Follower 的事务 Proposal,保证了一个同步的顺序性

Follower 收到事务 Proposal 之后,就立即写入本地磁盘日志中,写入成功后数据就不会丢失了,之后返回 Ack 给 Leader,当过半的 Follower 都返回 Ack,Leader 推送 Commit 消息给全部 Follower,让大家进行事务提交,事务提交之后,数据就被写入到了 znode(也就是内存中) ,此时数据就可以被用户感知到了

1704556482793

  • ZK 的 ZAB 保证集群的崩溃恢复

下边将会介绍 ZK 集群 启动 再到 崩溃 再到 恢复 整体的流程:

ZK 集启动的时候,进入 恢复模式 ,选举一个 Leader 出来,然后 Leader 等待集群中过半的 Follower 跟他进行数据同步,只要过半的 Follower 完成数据同步,接着就退出恢复模式,可以对外提供服务了

此时,还没完成同步的 Follower 会自己去跟 Leader 进行数据同步的

之后会进入 消息广播模式 ,只有 Leader 可以接受写请求,但是客户端可以任意连接 Leader 或者 Follower,如果客户端连接到 Follower,Follower 就会将写请求转发给 Leader

Leader 收到写请求,就把请求同步给所有的 Follower,当超过半数的 Follower 都返回了 Ack,之后 Leader 先将数据写到自己的 znode 中,再给所有的 Follower 发一个 Commit 消息,让大家提交这个请求事务,Follower 收到 Commit 消息后,就会将磁盘中刚刚写入的数据往内存中的 znode 中写,之后客户端就可以读取到数据了

如果 Leader 宕机了,就会进入 恢复模式 ,重新选举一个 Leader,只要获得了过半的机器的投票,就可以成为 Leader

ZK 集群中可以容忍不超过一半的机器宕机,就比如说一个集群有 3 台机器,那么最多允许 1 台机器宕机,剩下的 2 台选举 Leader,只要 2 台机器都认可其中一台机器当 Leader,也就是超过了集群一半的机器都认可,那么就可以选举这台机器作为 Leader

新的 Leader 等待过半的 Follower 跟他同步,之后重新进入 消息广播模式

以上就是 ZK 集群恢复崩溃的整个流程了,当然我也画了一个流程图,更方便观看,如下:

1704556288655

主要就是分为 3 个阶段:

  • 集群启动时:恢复模式,Leader 选举 + 数据同步

  • 消息写入时:消息广播模式,Leader 采用 2PC 的过半写机制,给 Follower 进行同步

  • 崩溃恢复:恢复模式,Leader/Follower 宕机,只要剩余机器超过一半,就可以选举新的 Leader

  • ZK 集群的性能瓶颈在哪里呢?

瓶颈在于 Leader 的 写性能,如果 ZK 集群挂掉的话,那么很有可能就是 Leader 的写入压力过大,这对一个公司的技术平台打击是巨大的,因为像 kafka 之类的技术都是强依赖 ZK 的,Dubbo + ZK 去做服务框架的话,当服务实例达到上万甚至几十万时,大量服务的上线、注册、心跳的压力达到了每秒几万甚至十万,单个 Leader 抗几万的请求还行,十几万的话 ZK 单个 Leader 是扛不住这么多的写请求的

想要提升 Leader 的 写性能 ,目前来说也就是提升部署 ZK 的机器性能了,还有一种方式也就是将 dataLogDir 目录挂载的机器上配置 SSD 固态硬盘,以此来提升事务日志 写速度 来提升写性能!

  • ZK 集群的 Leader 选举

在 Leader 选举时,需要用到以下几个属性:

SID :服务器 ID,和 myid 一致,作为服务器的标识,不可以重复

ZXID :事务 ID,用来标识一次服务状态的变更,ZXID 全局唯一并且递增,有 64 位,高 32 位时 Leader 的 Epoch,低 32 位是递增计数器

Epoch :每个 Leader 任期的代号(没有 Leader 时,同一轮投票过程中的 Epoch 时相同的,每投完一次票,就会加 1)

当一台机器进入 Leader 选举时,当前集群可能处于以下两种状态:

  • 集群中已经有一个 Leader

如果已经有 Leader 的情况,会被告知当前服务器的 Leader 信息,之后进行状态同步即可

  • 集群中确实不存在 Leader

假设 zookeeper 有 5 台服务器,SID 分别为 1、2、3、4、5,ZXID 分别为 8、8、8、7、7,并且 SID = 3 的服务器是 Leader

如果某一时刻服务器 3 和 5 出现故障,之后服务器 1、2、4 开始 Leader 选举,规则如下:

1、EPOCH 大的选举为 Leader

2、EPOCH 相同,事务 ID 大的选举为 Leader

3、事务 ID 相同,SID 大的选举为 Leader

那么对于服务器 1、2、4 来说,最终服务器 2 选举为 Leader, 这样的选举策略可以保证有 最新数据的节点 可以竞选

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

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

相关文章

Gartner 公布 2024 年八大网络安全预测

近日,Gartner 安全与风险管理峰会在悉尼举行,旨在探讨网络安全的发展前景。 本次峰会,Gartner 公布了 2024 年及以后的八大网络安全预测。 Gartner 研究总监 Deepti Gopal 表示,随着 GenAI 的不断发展,一些长期困扰网…

PL/SQL的词法单元

目录 字符集 标识符 分隔符 注释 oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 PL/SQL块中的每一条语句都必须以分号结束。 一个SQL语句可以跨多行,但分号表示该语句的结束:一行中也可以有多条 SQL语句&…

C++从入门到精通——命名空间

命名空间 前言一、命名空间引例什么是命名空间 二、命名空间定义正常的命名空间定义嵌套的命名空间多个相同名称的命名空间 三、命名空间使用加命名空间名称及作用域限定符使用using将命名空间中某个成员引入使用using namespace 命名空间名称引用引用命名空间和引用头文件有什…

javaScript | 报错:JSX expressions must have one parent element

#错误记录:在做一个练习时候出现这个错误 #错误原因分析:在React和JSX中,每个JSX表达式都必须有一个父元素。这意味着你想要渲染的所有组件或元素都必须被一个单独的容器所包含。这个规则的原因是JSX最终会被编译成调用React.createElement()…

librdkafka的简单使用

文章目录 摘要kafka是什么安装环境librdkafka的简单使用生产者消费者 摘要 本文是Getting Started with Apache Kafka and C/C的中文版, kafka的hello world程序。 本文完整代码见仓库,这里只列出producer/consumer的代码 kafka是什么 本节来源&#…

腾讯云优惠券领取及使用常见问题解答

随着云计算的普及,腾讯云作为国内领先的云计算服务提供商,为越来越多的企业和个人提供了丰富的云产品和服务。为了帮助用户更好地了解和使用腾讯云优惠券,本文将为大家解答关于腾讯云优惠券领取及使用的常见问题。 一、腾讯云优惠券概述 腾讯…

幻兽帕鲁服务器多少钱?2024年Palworld服务器价格整理

2024年全网最全的幻兽帕鲁服务器租用价格表,阿里云幻兽帕鲁游戏服务器26元1个月、腾讯云32元一个月、京东云26元一个月、华为云24元1个月,阿腾云atengyun.com整理最新幻兽帕鲁专用4核16G、8核16G、8核32G游戏服务器租用价格表大全: 阿里云幻…

vue3+Pinia的使用 - 封装

目录: persist.ts 可存储到本地 import { PersistedStateOptions } from "pinia-plugin-persistedstate";/*** description pinia 持久化参数配置* param {String} key 存储到持久化的 name* param {Array} paths 需要持久化的 state name* return per…

EfficientVMamba:Atrous Selective Scan for LightWeightVisualMamba

摘要 https://arxiv.org/pdf/2403.09977.pdf 先前的轻量级模型开发努力主要集中在基于CNN和Transformer的设计上,但仍面临持续的挑战。CNN擅长局部特征提取,但会牺牲分辨率,而Transformer提供了全局范围,但会加剧计算需求 O ( N…

苹果CMS影视APP源码,二开版本带视频教程

编译app教程 工具下载:Android Studio 官网地址:https://developer.android.google.cn/studio/ 环境设置: 设置中文:https://blog.csdn.net/qq_37131111/article/details/131492844 汉化包找最新的下载就行了,随便下载…

如何压缩视频到最小?教会你压缩原理~

在网上上传视频时,经常会遇到因为视频体积过大上传失败等情况发生,怎么降低视频体积呢?科普一个小知识:视频体积和视频的时长、编码格式、分辨率和比特率(又称码率)有关。视频文件大小计算公式:…

脚本实现Ubuntu设置屏幕无人操作,自动黑屏

使用 xrandr 命令可以实现对屏幕的控制,包括调整分辨率、旋转屏幕以及关闭屏幕等。要实现 Ubuntu 设置屏幕在无人操作一段时间后自动黑屏,非待机,并黑屏后点击触摸屏可以唤醒屏幕,可以借助 xrandr 命令来实现。 首先,…

Microsoft Edge浏览器修改网页背景颜色

目录 一、原始页面二、Microsoft Edge网页背景颜色修改三、Microsoft Edge主体颜色修改四、最终效果五、总结 一、原始页面 下面是大多数默认的网页界面。 二、Microsoft Edge网页背景颜色修改 在Microsoft Edge网页地址栏中输入下面指令: edge://flags在搜索框…

快速上手Spring Cloud 十三:探究Spring Cloud在跨境业务中的应用与优势

快速上手Spring Cloud 一:Spring Cloud 简介 快速上手Spring Cloud 二:核心组件解析 快速上手Spring Cloud 三:API网关深入探索与实战应用 快速上手Spring Cloud 四:微服务治理与安全 快速上手Spring Cloud 五:Spring …

Netty剖析 - Why Netty

文章目录 Why NettyI/O 请求的两个阶段I/O 模型Netty 如何实现自己的 I/O 模型线程模型 - 事件分发器(Event Dispather)弥补 Java NIO 的缺陷更低的资源消耗网络框架的选型Netty 发展现状Netty 的使用思维导图 Why Netty I/O 模型、线程模型和事件处理机…

货币系统(闫氏DP分析法)

题目描述: 给定 V 种货币(单位:元),每种货币使用的次数不限。 不同种类的货币,面值可能是相同的。 现在,要你用这 V 种货币凑出 N 元钱,请问共有多少种不同的凑法。 输入格式&am…

深入Facebook的世界:探索数字化社交的无限可能性

引言 随着数字化时代的到来,社交媒体平台已经成为了人们日常生活中不可或缺的一部分,而其中最为突出的代表之一便是Facebook。作为全球最大的社交媒体平台之一,Facebook不仅仅是一个社交网络,更是一个数字化社交的生态系统&#…

Windows/Linux-openEuler系统使用路由侠内网穿透,部署项目详细教程

文章目录 Windows/Linux-openEuler系统使用路由侠内网穿透,部署项目详细教程一、在windows系统下载安装路由侠并实现项目部署1、下载路由侠并注册安装到Windows系统2、点击内网映射,添加映射,注册域名前缀3、选择网站应用4、配置你想要代理项…

【Bug-ModuleNotFoundError: No module named ‘models‘】

🚀 作者 :“码上有前” 🚀 文章简介 :Python 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 出现这个错误: 出现了ModuleNotFoundError: No module named models’的问题。 文件在Model…

「吞噬星空」存在哪些境界,不朽级呼延博是否有一席之位?

吞噬星空中浩瀚无垠的宇宙,其深邃与广阔,仿佛一个无尽的迷宫,蕴藏着无数未知的境界。从地球出发,见证了行星级与恒星级的威能,然而这只是宇宙力量的冰山一角。行星级强者,在地球上已是至高无上的存在&#…