ZooKeeper 基础知识总结

先赞后看,Java进阶一大半

ZooKeeper 官网这样介绍道:ZooKeeper 是一种集中式服务,用于维护配置信息、命名、提供分布式同步和提供组服务。

在这里插入图片描述

各位hao,我是南哥,相信对你通关面试、拿下Offer有所帮助。

⭐⭐⭐一份南哥编写的《Java学习/进阶/面试指南》:https://github/JavaSouth

1. ZooKeeper的协议

1.1 ZAB协议

面试官:知道ZAB协议吗?

要深入学习ZooKeeper前,南哥认为我们要先学习ZooKeeper的核心理念,所有的ZooKeeper行为都是围绕这个核心来进行的。说了那么多,它就是——ZAB协议。

ZAB协议英文全称叫ZooKeeper Atomic Broadcast,我们透过中文含义可以大概了解他做了什么事情:ZooKeeper原子消息广播协议。

来看看原子广播在维基百科的解释。

在容错分布式计算中,原子广播或全序广播是指多进程系统中的所有正确进程都以相同顺序接收同一组消息(即相同的消息序列)的广播。

那ZooKeeper广播啥呢?我们知道ZooKeeper集群有Leader服务器、Follower服务器,这个Leader服务器接收了客户端所有的事务请求,事务请求可以是新增某一个ZNode节点,也可以是删除某一个ZNode节点。

这些事务请求的变更要不要提交、如何通知其他Follower服务器进行同步变更,这就是广播涉及的主要内容了。

ZAB协议主要包含了消息广播、崩溃模式,跟着南哥往下看看。

1.2 消息广播

面试官:消息广播你讲一讲?

ZAB协议的消息广播类似于二阶段提交过程。顾名思义事务最终的提交要分为两个阶段。

消息广播的流程如下:

(1)针对客户端的事务请求,Leader服务器会为其生成对应的事务Proposal,同时广播给集群中其余Followr机器。这个事务Proposal我们可以把他理解为事务提案。

(2)Follower服务器在接收到事务Proposal后会以事务日志形式写入到本地磁盘中,如果写入成功,则反馈一个Ack反馈给到Leader服务器。

(3)Leader服务器会收集其他Follower服务器的选票,只有半数的Follow服务器同意本次事务请求,那Leader服务器就会广播一个Commit消息,通知所有Follower服务器进行事务提交。

总结下来,也就是分为二个阶段,第一阶段是询问事务Proposal的写入尝试能否成功,第二阶段就是在Leader服务器、Follower服务器进行事务提交。

在这里插入图片描述

1.3 消息广播的缺点

面试官:那二阶段提交有什么缺点吗?

当然消息广播的二阶段提交有所缺点。

(1)在消息广播的第二阶段,如果有部分Follower服务器没有收到Leader服务器广播的事务提交消息,这就会出现数据不一致的情况了。

(2)单点问题。如果Leader服务器在第二阶段奔溃了,那其他Follower服务器仍然会处于锁定上一次事务资源的状态中。

(3)同步阻塞问题。参与一个客户端事务请求时,Leader、Follower服务器的其他逻辑都需要进行阻塞,直到等到上一个二阶段提交完成之后才会开始执行。

1.4. 崩溃模式

面试官:崩溃模式呢?

ZAB协议涉及Leader服务器、Follower服务器,Leader服务器充当了最重要的作用。如果Leader服务器崩溃了或者失去和Follwer服务器之间的联系,那上面南哥提到的二阶段提交各种问题很可能都会出现。

开头不是说ZAB协议包含了消息广播、崩溃模式?别慌,崩溃模式就是为此而生的。

崩溃模式总的来说就做了两个事情,我们记住这两点方便理解:一个是确保提交已经被Leader提交的事务Proposal,另一个是丢弃已经被跳过的事务Proposal。

(1)为了解决上文的第1点问题。Leader服务器会为每一个Follower服务器都准备一个Proposal消息队列,通过该队列发送那些没有被各Follower服务器同步的事务Proposal,同时在Proposal消息后面加上Commit消息让Follower服务器进行事务提交。这可以解决二阶段提交带来的数据不一致问题。

(2)为了解决上文的第2点问题。ZooKeeper设计了一个高32位的epoch,用来作为Leader服务器的标识;设计了一个低32位的事务偏移量ZXID,用来作为最新已提交事务的偏移量。

新的Leader服务器上线后,新的Leader服务器拥有集群里最大的事务偏移量,Leader服务器会和Follower服务器的ZXID进行比对,从而让Follower服务器回退被跳过的事务Proposal。

2. ZooKeeper数据模型

2.1 ZooKeeper数据节点

面试官:你说说ZooKeeper数据模型?

ZooKeeper的数据模型是一颗树结构,每一个树节点是一个数据节点,我们称它为ZNode

而每一个ZNode的节点路径标识使用斜杠/作为分隔符,我们可以在ZNode节点下写入数据、创建节点,这种斜杠/作为路径分隔符的方式和Unix文件系统路径非常相似。

大家可以看下Unix文件系统路径,以斜杠/作为路径分隔符。

# 根目录
/
# 可执行文件所在位置
/bin
# 设备驱动
/dev

这是ZooKeeper数据模型概念图,是不是非常类似呢?

在这里插入图片描述

另外ZooKepper这种斜杠/作为路径分隔符正好和Windows相反,Windows使用的是反斜杠\

# Windows路径示例
C:\Java\jdk1.8.0_311

2.2 数据节点类型

面试官:那ZooKeeper数据节点有几种类型?

ZooKeeper一共有四种节点类型,但从整体来看主要是持久节点类型、临时节点类型这两种,另外两种类型只是在以上两种节点类型基础上增加了顺序的特性。大家这样理解会更方便记忆~

  1. 持久节点:这种数据节点一旦背创建后,就会一直存在于ZooKeeper服务器上,除非对该数据节点执行删除操作。
  2. 持久顺序节点:刚刚和大家说了,该节点类型就是在持久节点基础上增加了顺序的特性。如果在持久顺序节点类型的父节点创建子节点,ZooKeeper会为该子节点名加上一个数字后缀来维护子节点的顺序。
  3. 临时节点:临时节点比较特殊,它的生命周期是和客户端会话绑定在一起的。这个客户端可以是连接ZooKeeper的某一个终端命令窗口,也可以是连接ZooKeeper的某一个Spring服务线程。如果客户端会话失效了,那这个临时节点就会被自动清除。
  4. 临时顺序节点:在临时节点的基础上添加了顺序特性。

另外大家记住一点,临时节点只能作为叶子节点,是不能在临时节点下面创建任何子节点的。原因大概是临时节点子节点没有存在的意义,创建子节点的场景大多是基于持久节点的场景,这种设计也可以防止对临时节点的误用。

2.3 数据节点的版本

面试官:数据节点版本知道吧?

ZooKeeper数据节点的版本概念和CAS操作的版本概念是一样的,同样是在多线程环境下,通过乐观锁这种无锁操作来保证线程安全性。

当一个数据节点被创建后,该节点的version值为0,代表它被更新过0次,如果后续对该节点进行更新操作,那version便会递增。

对数据节点的每次更新,都会对比数据节点的version是否是预期值,只有符合预期值,才会将新值更新到该数据节点。

大家可以通过以下CAS例子代码来了解CAS操作的执行过程。

@Slf4j
public class CAS implements Runnable {private static AtomicInteger val = new AtomicInteger(0);private void compareSwap(int expectVal, int operateVal) {if (val.compareAndSet(expectVal, operateVal)) {log.info("the thread called {} operated", Thread.currentThread().getName());} else {this.run(); // 相当于获取不到锁则重新执行}}@Overridepublic void run() {int curVal = val.get();log.info("the thread called {} get val is {}", Thread.currentThread().getName(), curVal);compareSwap(curVal, curVal + 1);}public static void main(String[] args) throws InterruptedException {CAS cas0 = new CAS();CAS cas1 = new CAS();Thread thread0 = new Thread(cas0, "cas0");Thread thread1 = new Thread(cas1, "cas1");thread0.start();thread1.start();thread0.join();thread1.join();log.info("current thread name: {} , the value of val: {}", Thread.currentThread().getName(), val);}
}控制台打印:
[ INFO ]the thread called cas0 get val is 0
[ INFO ]the thread called cas1 get val is 0
[ INFO ]the thread called cas0 operated
[ INFO ]the thread called cas1 get val is 1
[ INFO ]the thread called cas1 operated
[ INFO ]current thread name: main , the value of val: 2

2.4 事务ID

面试官:ZooKeeper事务ID呢?

我们熟悉的数据库事务一般是包含对数据库状态的读写操作,数据库事务具有ACID特性:原子性、一致性、持久性、隔离性。数据库事务这块大家有不懂的可以看我往期文章《MySQL事务的性情很“原子“,要么执行要么不执行》。

但ZooKeeper的事务和数据库事务大相径庭。ZooKeeper事务一般是包括对数据节点的创建、删除、更新,也包括客户端会话创建、失效情况对临时节点的影响。

每一个事务请求,ZooKeeper都会为其分配一个全局唯一的事务ID,我们称它为ZXID。所以ZXID也可以间接反映出对数据节点操作的全局顺序,这个全局顺序在Follower服务器对Leader服务器的数据复制上相当重要,可以用来保证数据的一致性。

2.5 Watcher机制

面试官:ZooKeeper数据变更通知使用什么对象?

ZooKeeper拥有分布式通知的功能,这个功能是基于Watcher机制来实现的。一个Watcher对象就像一个订阅者,当订阅的主题状态发生变化,就会通知Watcher订阅者作出一定动作。

Watcher机制的工作流程,首先是客户端向ZooKeeper服务器注册Watcher通知,接着会将Watcher对象存储在客户端本身的WatchManager中。当ZooKeeper服务器触发Watcher事件后会向客户端发起通知,客户端就从本身的WatchManager取出对应的Watcher对象来执行回调操作

Watcher机制的大致流程大家可以参考下图:

在这里插入图片描述

3. ZooKeeper分布式锁

3.1 排他锁实现分布式锁

面试官:知道Zookeeper有什么应用场景吗?

目前地球村里大型公司部署的分布式技术,绝大部分都是由Zookeeper提供底层的技术支持,所以Zookeeper多么重要就不用我多说了吧。

我们可以利用Zookeeper来完成分布式系统涉及的各种核心功能,例如以下4种:

  1. 数据发布/订阅。可以用来实现配置中心。

  2. 命名服务。类似于UUID,可以生成全局唯一的ID。

  3. 集群管理。每一个服务器是一个子节点,可以用来检测到集群中机器的上/下线情况。

  4. 分布式锁。

南哥先讲下我们可以怎么利用Zookeeper来实现分布式锁,要实现分布式锁,分为获取锁和释放锁两个步骤。

ZooKeepr获取锁时会在/exclusive_lock节点下创建子节点,如果创建成功则获得锁。如果创建失败,则访问Zookeeper的客户端会在该节点注册一个Watcher监听,用来实时监控子节点的变更从而重新获得锁,这有点类似于线程的循环等待。

当要释放锁时,Zookeeper会删除该子节点,此时/exclusive_lock节点下就有空位了。Watcher监听则通知客户端可以重新创建子节点来获得锁资源。

在这里插入图片描述

3.2 共享锁实现分布式锁

面试官:你说的是排他锁,共享锁呢?

大家有没发现,上面分布式锁的实现方式是排他锁,我们也可以使用共享锁的实现方式,来看看两者的区别。

排他锁,又称为写锁或独占锁,是一种基本的锁类型。如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能再对这个数据对象进行任何类型的操作——直到T1释放了排他锁。

共享锁,又称为读锁,同样是一种基本的锁类型。如果事务T1对数据对象O1加上了共享锁,那么当前事务只能对O1进行读取操作,其他事务也只能对这个数据对象加共享锁——直到该数据对象上的所有共享锁都被释放。

Zookeeper以共享锁方式来实现分布式锁,每次读、写请求都会去创建子节点,这是一个类似于“/shared_lock/[Hostname]-请求类型-序号”的临时顺序节点

每一个要获得分布式锁的客户端都会去获取子节点列表,同时注册Watcher监听,读、写这两步有不同的步骤。

(1)获取读锁的话,如果前面比自己小的序号没有写请求,则表示可以读。

(2)获取写锁的话,只有在自己是序号最小的情况下,才可以读成功。

另外共享锁的释放锁和排他锁都是一样的,只需要删除所创建的子节点就可以。

3.3 共享锁羊群效应

面试官:有没听说过共享锁的羊群效应?

大家要注意下,共享锁来实现分布式锁,在集群规模比较大的场景下,可能会出现羊群效应。

什么是羊群效应?我们看看百度百科的解释。

羊群效应是个人的观念或行为由于真实的或想象的群体的影响或压力,而向与多数人相一致的方向变化的现象。

其实共享锁的特别之处,在于每次读、写请求都要注册Watcher监听来获取子节点列表,特别是数量更多的读请求,每1分钟可能是上百万次的请求。

以共享锁来实现,子节点列表只要每次一变动,就要通知所有的服务器客户端。这明显造成了短时间大量的事件通知,给Zookeeper带来的性能消耗是巨大的。

3.4 处理羊群效应

面试官:那怎么解决呢?

如何看待共享锁带来的羊群效应,我们从两个方面来看待。如果在集群不大的情况下羊群效应发生带来的影响不会太大,而且这种设计简单实用

而如果在集群规模大的场景下,我们可以这样改进。客户端的读、写请求首先获取子节点列表,但都不注册Watcher监听

(1)读请求:只向比自己序号小的最后一个写请求节点注册Watcher监听。

(2)写请求:只向比自己序号小的最后一个节点注册Watcher监听。

这样的设计就可以避免羊群效应,主要是从监听子节点列表,改进为只监听某个子节点

3.5 Kafka应用场景

面试官:Kafka应用场景呢,知道Kafka是怎么利用Zookeeper吗?

南哥了解到的Kafka利用Zookeeper的主要有 4 点,我们来看看。

(1)使用Zookeeper来对所有Broker服务器、Topic进行管理。Broker启动后都会到Zookeeper上创建属于自己的临时节点,其节点路径为/broker/ids/[0…N],注册Topic节点也是一样。

(2)而在Kafka防止消费重复消费方面,消费者消费消息后,都会在消息分区写入临时节点,代表该消息已消费。

(3)另外在Kafka生产者负载均衡方面,Kafka消息生产者会通过监听Broker节点列表,负载均衡地分发到某一个Broker。

(4)在消费者负载均衡有两方面。一方面,每一个消费者服务器都会在Zookeeper创建消费者节点。当有新消息时,Kafka就可以通过Zookeeper的消费者节点列表负载均衡地通知某个消费者;另一方面,Kafka将一个Topic分成了多个分区,多个分区由不同的Broker处理,这是实现对Broker的负载均衡

我是南哥,南就南在Get到你的点赞点赞点赞。

在这里插入图片描述

看了就赞,Java进阶一大半。点赞 | 收藏 | 关注,各位的支持就是我创作的最大动力❤️

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

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

相关文章

玩转 Burp Suite (1)

内容预览 ≧∀≦ゞ 玩转 Burp Suite (1)声明Burp Suite 简介Dashboard(仪表盘)1. 默认任务管理2. 暂停任务3. 新建扫描任务4. 使用总结 Target(目标)1. SIte Map (站点地图)2. Scope(范围&#…

BGP协议路由黑洞

一、实验环境 1、分公司与运营商AS自治系统内运行IGP路由协议OSPF、RIP或静态路由,AS自治系统内通过IBGP路由协议建立BGP邻居关系。 2、公司AS自治系统与运营商AS自治系统间运行EBGP路由协议。 3、通过loopback建立IBGP与EBGP邻居关系,发挥loopback建立…

ThinkPHP Nginx 重写配置

目录 NGINX 重写 Admin项目隐藏入口文件,且禁用Admin模块&Admin.php 1️⃣配置仅用模块 2️⃣新增admin_xyz.php文件(自定义入口文件名),并绑定admin模块 3️⃣配置nginx 重写规则 NGINX 重写 在Nginx低版本中&#xff0…

k8s集群增加nfs-subdir-external-provisioner存储类

文章目录 前言一、版本信息二、本机安装nfs组件包三、下载nfs-subdir-external-provisioner配置文件并进行配置1.下载文件2.修改配置 三、进行部署备注:关于镜像无法拉取问题的处理 前言 手里的一台服务器搭建一个单点的k8s集群,然后在本机上使用nfs-su…

百度 文心一言 vs 阿里 通义千问 哪个好?

背景介绍: 在当前的人工智能领域,随着大模型技术的快速发展,市场上涌现出了众多的大规模语言模型。然而,由于缺乏统一且权威的评估标准,很多关于这些模型能力的文章往往基于主观测试或自行设定的排行榜来评价模型性能…

Python 爬虫指定数据提取【Xpath】

Xpath 是一个非常好用的解析方法&#xff0c;使用前需要安装对应的库&#xff0c;这个自行搜索&#xff0c;很简单&#xff01; 示例代码 from lxml import etree text <div><ul><li class"item-0"><a href"link1.html">first …

ESP32学习笔记_Peripherals(1)——UART

摘要(From AI)&#xff1a; 这篇博客详细讲解了 ESP32 UART 通信的基础知识、配置流程和实践代码&#xff0c;涵盖了 UART 的工作原理、API 使用方法以及实际应用场景&#xff0c;结合完整的代码示例展示了如何与外部设备&#xff08;如 4G 模块&#xff09;进行串口通信。内容…

UE5 实现组合键触发事件的方法

因为工作原因。 需要用大括号{和}来触发事件 但是在蓝图中搜了一下&#xff0c;发现键盘事件里根本就没有{}这两个键。 花费了一下午&#xff0c;终于找到解决的方法了&#xff0c;也就是增强输入的弦操作 首先创建一个项目 纯蓝图或者C都可行 进入到内容浏览器的默认页面 …

富文本编辑器图片上传并回显

1.概述 在代码业务需求中&#xff0c;我们会经常涉及到文件上传的功能&#xff0c;通常来说&#xff0c;我们存储文件是不能直接存储到数 据库中的&#xff0c;而是以文件路径存储到数据库中&#xff1b;但是存储文件的路径到数据库中又会有一定的问题&#xff0c;就是 浏览…

JVM指令集概览:基础与应用

写在文章开头 在现代软件开发中,Java 语言凭借其“一次编写,到处运行”的理念成为了企业级应用的首选之一。这一理念的背后支撑技术正是 Java 虚拟机(JVM)。JVM 是一个抽象的计算机,它实现了 Java 编程语言的各种特性,并且能够执行编译后的字节码文件。了解 JVM 的工作原…

麒麟系统x86安装达梦数据库

一、安装准备前工作 操作系统&#xff1a;银河麒麟V10&#xff0c;CPU&#xff1a; x86_64 架构 下载地址&#xff0c;麒麟官网&#xff1a;https://www.kylinos.cn/ 数据库&#xff1a;dm8_20220915_x86_kylin10_64 下载地址&#xff0c;达梦数据库官网&#xff1a;https://…

力扣 二叉树的中序遍历

用了递归遍历&#xff0c;关于树的经典例题。 题目 递归 常规做法即递归了&#xff0c;不会写也得背下来。递归可以大致理解方法调用自身&#xff0c;先写中序遍历递归的方法&#xff0c;递归一定要有递归出口&#xff0c;当遍历到节点为空时返回&#xff0c;即已经找到了。…

windows server 2019 启动 nginx 报错

环境 &#xff1a;windows server 2019 &#xff0c;nginx-1.19.7 背景&#xff1a; 自己经常用这个 nginx 包作为 web 服务器。今天发现 部署到 server 2019 上直接报错了。这可是原生的包&#xff0c;我啥也没改&#xff0c;怎么可能报错。而且之前在 其他服务器用都没问题…

python代码示例(读取excel文件,自动播放音频)

目录 python 操作excel 表结构 安装第三方库 代码 自动播放音频 介绍 安装第三方库 代码 python 操作excel 表结构 求出100班同学的平均分 安装第三方库 因为这里的表结构是.xlsx文件,需要使用openpyxl库 如果是.xls格式文件,需要使用xlrd库 pip install openpyxl /…

百度智能云发布首个空间智能解决方案,百度AI优势如何分析?

首先&#xff0c;百度智能云此次推出的空间智能解决方案&#xff0c;在技术底座上展现了其强大的AI异构计算能力。百度百舸AI异构计算平台作为该方案的底层支撑&#xff0c;为2D和3D应用中的人物、物件及场景生成提供了强大的算力支持。这一平台的推出&#xff0c;不仅提升了空…

深度学习-49-AI应用实战之基于HyperLPR的车牌识别

文章目录 1 车牌识别系统1.1 识别原理1.1.1 车牌定位1.1.2 字符识别2 实例应用2.1 安装hyperlpr32.2 识别结果2.3 可视化显示2.4 结合streamlit3 附录3.1 PIL.Image转换成OpenCV格式3.2 OpenCV转换成PIL.Image格式3.3 st.image嵌入图像内容3.4 参考附录1 车牌识别系统 车牌识别…

非递归遍历二叉树(数据结构)

我的博客主页 非递归遍历二叉树 前序遍历&#xff08;迭代&#xff09;中序遍历&#xff08;迭代&#xff09;后续遍历&#xff08;迭代&#xff09; 二叉树的遍历方式有&#xff1a;前序遍历、中序遍历、后续遍历&#xff0c;层序遍历&#xff0c;而树的大部分情况下都是通过递…

丹摩征文活动|实现Llama3.1大模型的本地部署

文章目录 1.前言2.丹摩的配置3.Llama3.1的本地配置4. 最终界面 丹摩 1.前言 Llama3.1是Meta 公司发布的最新开源大型语言模型&#xff0c;相较于之前的版本&#xff0c;它在规模和功能上实现了显著提升&#xff0c;尤其是最大的 4050亿参数版本&#xff0c;成为开源社区中非常…

基于stm32单片机的教室节能系统设计

功能描述 0. STM32F103C8T6单片机为控制核心 1. OLED液晶显示当前年 月 日 时 分 秒 星期 2. 按键可以设置定时时间 3. 按键可以设置用电开关的开启和关闭时间&#xff0c;实现设备的节能 4. 通过红外遥控可以打开关闭空调设备&#xff08;通过继电器开关闭合模拟&#x…

防止按钮被频繁点击

在做开发的时候,不希望按钮被用户频繁点击,给后端服务器增加负担,这个时候,可以在按钮的触发函数加上如下代码: // 禁用按钮 const fetchButton document.querySelector(.btn-fetch); fetchButton.disabled true; // 延时61秒后重新启用按钮 setTimeout(() > { fetchBut…