当前位置: 首页 > news >正文

【分布式】Zookeeper

Java开发者视角下的Zookeeper—— 在什么场景下使用,怎么用

可以参考:https://zhuanlan.zhihu.com/p/62526102

Zookeeper是什么?

ZooKeeper 是一个分布式的,开放源码的分布式应用程序协同服务。ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

应用场景

  • 配置管理。 Java微服务系统,对于各个独立服务都要使用集中化的配置管理,此时可以用到Zookeeper
  • DNS服务
  • 组成员管理
  • 分布式锁

适用于存储和协同相关的关键数据,不适合大数据量存储。 因为zookeeper需要把所有数据加载到内存中,所存储的数据量受到内存的限制; zookeeper存储关键数据,保证数据的高可用性和性能才是它的设计目的。
可以看一下Java开发者的相关文章,Kafka用到zookeeper,所以说想要使用Kafka,两个都得装上。 kafka使用zookeeper来管理自己的元数据配置; 在实现分布式锁的情境下,也会使用到zookeeper。

分布式系统开发视角——怎么设计,需要设计哪些API

内容参考MIT6.824:https://mit-public-courses-cn-translatio.gitbook.io/mit6-824/lecture-08-zookeeper/8.4-zookeeper

特点1: Zookeeper是一个通用的协调服务
如果想要使用Raft,那么设计自己的应用程序与Raft交互。 Zookeeper就是把分布式服务给封装了,然后提供API, 它使用的一致性协议是ZAB

特点2: Zookeeper 一写多读, 性能提升但是不保证强一致性
如果要求系统的强一致性,增加server数量并不能提升系统性能
性能瓶颈在于leader, leader需要处理每一个请求,将请求的拷贝发送给每一个其他服务器,非leader节点的增加并不能实际完成任何工作。

针对该问题的改进:一写多读,只有写请求需要经过leader,读请求不需要经过leader。 在现实世界中,读请求比写请求多得多,比如web页面,都是通过读请求来生成web页面。
但是,如果把客户端请求发送给副本,能否得到预期结果?副本中的数据,并不一定是最新的,因为append entries只要求大多数节点收到并响应,我们需要读的节点也许为少数节点,此时数据是落后的。

一致保证Consistency Guarantees

对于Zookeeper来说,并不要求返回最新的写入数据。 Zookeeper放弃线性一致性,不提供线性一致的读。它有自己有关一致性的定义, 两个主要的保证:

  1. 写请求是线性一致的 linearable writes

尽管客户端可以并发的发送写请求,然后Zookeeper表现的就像以某种顺序,一次只执行一个写请求,并且也符合写请求的实际时间。所以如果一个写请求在另一个写请求开始前就结束了,那么Zookeeper实际上也会先执行第一个写请求,再执行第二个写请求。

  1. 任何一个客户端的请求,都会按照客户端指定的顺序来执行,论文里称之为FIFO(First In First Out)客户端序列 FIFO client order

对于写请求,最终会以客户端确定的顺序执行。这一点可以理解为,请求的执行顺序按照客户端发出指令的时间为准(?),客户端可以发送异步的写请求,服务端的执行顺序就按照客户端发送请求的时间(序号)。

对于读请求,如果第一个读请求在Log中的一个位置执行,那么第二个读请求只允许在第一个读请求对应的位置或者更后的位置执行。 (也就是读读一致性的要求)这个位置也就是Log对应的条目号zxid,每次读请求的响应中会带上zxid给client, 当client再次发出请求到一个相同或者不同的副本时,会在请求中带上最高的zxid,这样副本就会知道,至少要在Log中的这个点或之后执行读请求。 如果这个副本的最新日志小于zxid,那么就无法响应客户端请求(这里可以是发出信息拒绝client,或是一直阻塞),直到log更新,才能响应client的读请求。

如果客户端先发送写请求,紧接着发读请求,此时需要写请求执行以后,才能接着处理读请求。这是为了满足写读一致性。 为了处理这种情况,客户端的读请求还要带上 上一次写请求对应的zxid, 副本必须看到对应zxid的写请求才能再执行读请求。

同步操作 sync

zookeeper有一个弥补非严格线性一致的方法 —— sync
假设现在需要刚刚写入的最新的数据,可以发送sync请求(本质上是写请求),让sync请求写入到所有副本的sync 。 我认为sync可以理解为一个标志点。
然后向副本发送读请求并携带信息告知(发送了sync这事), 副本需要在看到sync后才能回复这个读请求。 因为收到了sync,也就意味着收到了sync之前的所有日志。副本的响应至少是发送sync请求时对应的状态。
sync是个代价很高的操作,本来读请求是不经过leader的,发送sync后意味着客户端需要等待日志同步到sync的位置才能响应。

就绪文件 Ready file/znode

znode是zookeeper的数据点, file = znode, 和linux一致,“一切皆文件”

考虑zookeeper管理配置文件场景:Master节点更新一个存有集群信息的配置,而大量客户端需要读取配置,此时Master节点能做到原子更新吗? 客户端并不希望读到更新到一半的配置。
我希望zookeeper能够对读做一个限制,不读到中间状态。

zookeeper应对这种情况的方式:Ready file
如果Ready file存在,则client可以读取配置
如果Ready file不存在,client不能读取。

Master更新配置的流程:

  1. 删除Ready file
  2. 更新相关的配置文件
  3. 更新完成后,创建Ready file

所有步骤均为写请求,zookeeper可以确保这些请求以线性顺序执行。 对于副本,也需要按这一流程执行,在更新前删除Ready file, 更新后创建Ready file。
clinet若在此时发送读请求,副本发现ready file不存在,那么会过一会再重试。
结合一致保证章节中所提到的zookeeper写读一致性的实现, 如果客户端可以看见创建Ready file的写请求, 读请求必须在该写请求之后 => 因此,zookeeper可以保证读请求看到对配置的全部更新。

问题又来了: 客户端想要看见Ready file需要通过调用exist,客户端调用exist的时候Ready file存在,但是读完后master开始更新配置,这样带来的后果就是:配置虽然更新了,但是客户端还以为是老配置。
zookeeper的解决方法是: 客户端不仅会发送exists来查询Ready file是否存在,还会建立一个针对Ready file的watch通道。一旦Ready file改变,副本节点会向客户端发送通知。client处理完了发来的通知,再重新执行读配置的操作。

Zookeeper API

zookeeper可以用来解决的问题:

  • 比如VMware FT,它的主备切换需要test-and-set服务, zookeeper可以提供这样一种第三方服务
  • 发布服务器的配置信息
  • 选举master

zookeeper的API看起来像是文件系统, 请求zookeeper数据的时候需要指定路径(路径就像Linux文件路径一样),文件和目录都叫做znode,类别如下:

  • Regular znodes 创立即永久
  • Ephemeral znodes 与客户端会话绑定
  • Sequential znodes
  • CREATE(PATH,DATA,FLAG)。入参分别是文件的全路径名PATH,数据DATA,和表明znode类型的FLAG。这里有意思的是,CREATE的语义是排他的。也就是说,如果我向Zookeeper请求创建一个文件,如果我得到了yes的返回,那么说明这个文件之前不存在,我是第一个创建这个文件的客户端;如果我得到了no或者一个错误的返回,那么说明这个文件之前已经存在了。所以,客户端知道文件的创建是排他的。在后面有关锁的例子中,我们会看到,如果有多个客户端同时创建同一个文件,实际成功创建文件(获得了锁)的那个客户端是可以通过CREATE的返回知道的。
  • DELETE(PATH,VERSION)。入参分别是文件的全路径名PATH,和版本号VERSION。有一件事情我之前没有提到,每一个znode都有一个表示当前版本号的version,当znode有更新时,version也会随之增加。对于delete和一些其他的update操作,你可以增加一个version参数,表明当且仅当znode的当前版本号与传入的version相同,才执行操作。当存在多个客户端同时要做相同的操作时,这里的参数version会非常有帮助(并发操作不会被覆盖)。所以,对于delete,你可以传入一个version表明,只有当znode版本匹配时才删除。
  • EXIST(PATH,WATCH)。入参分别是文件的全路径名PATH,和一个有趣的额外参数WATCH。通过指定watch,你可以监听对应文件的变化。不论文件是否存在,你都可以设置watch为true,这样Zookeeper可以确保如果文件有任何变更,例如创建,删除,修改,都会通知到客户端。此外,判断文件是否存在和watch文件的变化,在Zookeeper内是原子操作。所以,当调用exist并传入watch为true时,不可能在Zookeeper实际判断文件是否存在,和建立watch通道之间,插入任何的创建文件的操作,这对于正确性来说非常重要。
  • GETDATA(PATH,WATCH)。入参分别是文件的全路径名PATH,和WATCH标志位。这里的watch监听的是文件的内容的变化。
  • SETDATA(PATH,DATA,VERSION)。入参分别是文件的全路径名PATH,数据DATA,和版本号VERSION。如果你传入了version,那么Zookeeper当且仅当文件的版本号与传入的version一致时,才会更新文件。
  • LIST(PATH)。入参是目录的路径名,返回的是路径下的所有文件。

举例:使用zookeeper实现计数器

错误做法:

count = GET(key)
// get 之后, count还有可能改变
PUT(k, count + 1)

因为read-update-write 不是原子的

正确做法:

WHILE TRUE:X, V = GETDATA("F") //read操作,任意副本执行IF SETDATA("f", X + 1, V): // write操作, leader执行。  //如果get后数据被修改,版本号就不是V,无法执行SET操作,会进行下一个循环BREAK

Test-and-set服务也可以这样实现。旧的数据为0, 想要将它设置为1,那么在set的时候需要带上旧的版本号,版本号必须与读时的版本号相同。

相关文章:

【分布式】Zookeeper

Java开发者视角下的Zookeeper—— 在什么场景下使用,怎么用 可以参考:https://zhuanlan.zhihu.com/p/62526102 Zookeeper是什么? ZooKeeper 是一个分布式的,开放源码的分布式应用程序协同服务。ZooKeeper 的设计目标是将那些复…...

ScheduleJS Crack,新的“信息列”水平滚动功能

ScheduleJS Crack,新的“信息列”水平滚动功能 增加了对Angular 16的支持 新的“信息列”水平滚动功能。 新的“信息列”固定功能。 添加了输入属性以处理组件模板中的偶数和奇数ScheduleRowPlainBackgroundColor以及CSS变量。 改进了“信息列”和角度甘特组件的类型。 Schedul…...

curl封装

一。由于工作的原因,需要对curl做一些封装,附加上我们的证书,提供给第三个C和jAVA使用。 二。头文件封闭四个函数,get,post,download,upload #ifndef CURLHTTP_H #define CURLHTTP_H#include …...

C语言数据类型和变量

C语言数据类型和变量 数据类型分类内置类型【C语言本身就具有的类型】自定义类型【自己来创建类型】取值范围 变量变量的创建变量创建的语法形式变量的分类全局变量局部变量 栈区、堆区、静态区 算术操作符赋值操作符连续赋值复合赋值符 单目操作符:、--、、-强制类…...

分布式训练 最小化部署docker swarm + docker-compose落地方案

目录 背景: 前提条件: 一、docker环境初始化配置 1. 安装nvidia-docker2 2. 安装docker-compose工具 3. 获取GPU UUID 4. 修改docker runtime为nvidia,指定机器的UUID 二、docker-swarm 环境安装 1. 初始化swarm管理节点 2. 加入工…...

QT学习笔记-开发环境编译Qt MySql数据库驱动与交叉编译Qt MySql数据库驱动

QT学习笔记-开发环境编译Qt MySql数据库驱动与交叉编译Qt MySql数据库驱动 0、背景1、基本环境2、开发环境编译Qt MySql数据库驱动2.1 依赖说明2.2 MySQL驱动编译过程 3、交叉编译Qt MySql数据库驱动3.1 依赖说明3.3.1 如何在交叉编译服务器上找到mysql.h及相关头文件3.3.2 如果…...

QT使用QXlsx实现数据验证与Excel公式操作 QT基础入门【Excel的操作】

准备环境:QT中使用QtXlsx库的三种方法 1、公式操作写单行公式 //右值初始化Format rAlign;rAlign.setHorizontalAlignment(Format::AlignRight);//左值初始化Format lAlign;lAlign.setHorizontalAlignment(Format::AlignLeft);xlsx.write("B3", 40, lAlign);xlsx.wr…...

renrenfast Vue2 打包发布

1、修改 static/config/index-prod.js 文件 // api接口请求地址 window.SITE_CONFIG[baseUrl] http://192.168.1.86:8080/renren-fast; /*** 生产环境*/ ;(function () {window.SITE_CONFIG {};// api接口请求地址window.SITE_CONFIG[baseUrl] http://192.16…...

NoSQL数据库介绍+Redis部署

目录 一、NoSQL概述 1、数据的高并发读写 2、海量数据的高效率存储和访问 3、数据库的高扩展和高可用 二、NoSQL的类别 1、键值存储数据库 2、列存储数据库 3、文档型数据库 4、图形化数据库 三、分布式数据库中的CAP原理 1、传统的ACID 1)、A--原子性 …...

【mindspore学习】环境配置

本次实验搭配的环境是 CUDA 11.6 CUDNN v8.9.4 TensorRT-8.4.1.5 mindspore 2.1.0。 1、配置 Nvidia 显卡驱动 如果原来的主机已经安装了 nvidia 驱动,为避免版本的冲突,建议先清除掉旧的 nvidia驱动 sudo apt-get --purge remove nvidia* sudo apt…...

基于shell脚本对aliyun npm仓库(https://packages.aliyun.com)登录认证

文章目录 基于shell脚本对阿里云npm仓库(https://packages.aliyun.com)登录认证食用人群食用方式 基于shell脚本对阿里云npm仓库(https://packages.aliyun.com)登录认证 食用人群 由于一些安全的原因,某些企业可能会…...

K8s Pod 安全认知:从openshift SCC 到 PSP 弃用以及现在的 PSA

写在前面 简单整理,博文内容涉及: PSP 的由来PSA 的发展PSA 使用认知不涉及使用,用于了解 Pod 安全 API 资源理解不足小伙伴帮忙指正对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是…...

提高企业会计效率,选择Manager for Mac(企业会计软件)

作为一家企业,良好的财务管理是保持业务运转的关键。而选择一款适合自己企业的会计软件,能够帮助提高会计效率、减少错误和节约时间。在众多的选择中,Manager for Mac(企业会计软件)是一款值得考虑的优秀软件。 首先,Manager for…...

软考:中级软件设计师:信息系统的安全属性,对称加密和非对称加密,信息摘要,数字签名技术,数字信封与PGP

软考:中级软件设计师:信息系统的安全属性 提示:系列被面试官问的问题,我自己当时不会,所以下来自己复盘一下,认真学习和总结,以应对未来更多的可能性 关于互联网大厂的笔试面试,都是需要细心准…...

Vue3中reactive响应式失效的问题

情景阐述 弹窗内部有一个挑选框,要通过请求接口获取挑选框下面可供选择的数据。 这是一个很简单的情境,我立刻有了自己的思路。如果实现搜索,数据较少可以直接用elementplus自带的filter。如果数据较多,就需要传val,…...

lamp

LAMP 环境 指的是在 Linux 操作系统中分别安装 Apache 网页服务器、MySQL 数据库服务器和 PHP 开发服务器,以及一些对应的扩展软件。AMP也支持win操作系统 (sccm 域升级版) LAMP架构是目前成熟的企业网站应用模式之一,指的是协同…...

LeetCode 周赛上分之旅 #42 当 LeetCode 考树上倍增,出题的趋势在变化吗

⭐️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度…...

Qt 自定义菜单 托盘菜单

托盘菜单实现:通过QSystemTrayIconQMenuQAction即可完美实现! 实现方式:createActions用于创建菜单、菜单项,translateActions用于设置文本、实现多语化,translateAccount用于设置用户空间配额。 void TrayMenu::createActions(…...

channel并发编程

不要通过共享内存通信,要通过通信共享内存。 channel是golang并发编程中一种重要的数据结构,用于多个goroutine之间进行通信。 我们通常可以把channel想象成一个传送带,将goroutine想象成传送带周边的人,一个传送带的上游放上物品…...

苹果新健康专利:利用 iPhone、Apple Watch 来分析佩戴者的呼吸情况

根据美国商标和专利局(USPTO)公示的清单,苹果获得了一项健康相关的技术专利,可以利用 iPhone、Apple Watch 来分析佩戴者的呼吸系统。 苹果在专利中概述了一种测量用户呼吸功能的系统,通过 iPhone 上的光学感测单元&am…...

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...