【分布式】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的时候需要带上旧的版本号,版本号必须与读时的版本号相同。

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

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

相关文章

【Python】从入门到上头— 高级特性(6)

文章目录 一.切片二.迭代三.列表生成式四.生成器五.迭代器 一.切片 取一个list或tuple的部分元素是非常常见的操作。比如,一个list如下: L [Michael, Sarah, Tracy, Bob, Jack]取前3个元素,应该怎么做? 笨办法 [L[0], L[1], L[2…

抽象轻松c语言

目 c语言 c程序 c语言的核心在于语言,语言的作用是进行沟通,人与人之间的信息交换 人与人之间的信息交换是会有信息空白(A表达信息,B接受信息,B对信息的处理会与A所以表达的信息具有差距,这段差距称为信…

keras深度学习框架通过简单神经网络实现手写数字识别

背景 keras深度学习框架,并不是一个独立的深度学习框架,它后台依赖tensorflow或者theano。大部分开发者应该使用的是tensorflow。keras可以很方便的像搭积木一样根据模型搭出我们需要的神经网络,然后进行编译,训练,测试…

用迅为i.MX6ULL开发板同一个网段概念

使用 nfs 之前,开发板、虚拟机 ubuntu、windows 电脑三者要互相 ping 通,这就涉及到了同一个网段 的概念。 概念:同一个网段是指 IP 地址和子网掩码相与得到的相同的网络地址。 快速判断同一个网段: (1&#xff09…

JVM 是怎么设计来保证new对象的线程安全

1、采用 CAS 分配重试的方式来保证更新操作的原子性 2、每个线程在 Java 堆中预先分配一小块内存,也就是本地线程分配缓冲(Thread Local AllocationBuffer,TLAB),要分配内存的线程,先在本地缓冲区中分配&a…

windows server 2019 安装sqlserver2012

在安装前,应先关闭系统防火墙 双击exe 选择【全新SQL Server独立安装或向现有安装添加功能】选项 运行完成后,如无失败或警告,点击确定,如果出现警告,需要处理掉再继续执行 点击下一步 勾选接受许可,点击下…

云原生Kubernetes:K8S概述

目录 一、理论 1.云原生 2.K8S 3.k8s集群架构与组件 二、总结 一、理论 1.云原生 (1)概念 云原生是一种基于容器、微服务和自动化运维的软件开发和部署方法。它可以使应用程序更加高效、可靠和可扩展,适用于各种不同的云平台。 如果…

【微服务部署】一、使用docker-compose部署Jenkins、SonarQube、PostgreSQL

一、安装 1、编写docker-compose部署Postgres、SonarQube、Jenkins的yml文件jenkins-compose.yml Postgres:作为SonarQube的数据库存储SonarQube:代码质量检查Jenkins:jenkins/jenkins:lts镜像,jenkinsci/blueocean镜像缺少node…

解决 filezilla 连接服务器失败问题

问题描述: 开始一直用的 XFTP 后来,它变成收费软件了,所以使用filezilla 代替 XFTP 之前用的还好好的,今天突然就报错了:按要求输入相关字段,连接 连接失败!!!o(╥﹏╥…

使用 BERT 进行文本分类 (03/3)

一、说明 在使用BERT(2)进行文本分类时,我们讨论了什么是PyTorch以及如何预处理我们的数据,以便可以使用BERT模型对其进行分析。在这篇文章中,我将向您展示如何训练分类器并对其进行评估。 二、准备数据的又一个步骤 …

Android系统修改驱动固定USB摄像头节点绑定前后置摄像头

前言 Android系统中usb摄像头节点会因为摄像头所接的usb口不同或者usb设备识别顺序不一样而出现每次开机生成的video节点不一样的问题。由于客户app调用摄像头时,需要固定摄像头的节点。因此需要针对前面的情况做处理。 方式1:通过摄像头名称固定摄像头节点 --- a/kernel…

友元(个人学习笔记黑马学习)

1、全局函数做友元 #include <iostream> using namespace std; #include <string>//建筑物类 class Building {//goodGay全局函数是 Building好朋友 可以访问Building中私有成员friend void goodGay(Building* building);public:Building() {m_SittingRoom "…

Eclipse错误提示: Symbol ‘xxxx‘ could not be resolved

问题现象&#xff1a; 调试FPGA时&#xff0c;如果在qsys中增加新的内容&#xff0c;到nios中编译的时候就会提示找不到宏定义。 而这些宏定义都是在system.h这个头文件中的&#xff0c;原来的宏定义都能找到&#xff0c;就是新增的找不到&#xff0c;这个应该和头文件路径没有…

信息熵 条件熵 交叉熵 联合熵 相对熵(KL散度) 互信息(信息增益)

粗略版快速总结 条件熵 H ( Q ∣ P ) 联合熵 H ( P , Q ) − H ( P ) 条件熵H(Q∣P)联合熵H(P,Q)−H(P) 条件熵H(Q∣P)联合熵H(P,Q)−H(P) 信息增益 I ( P , Q ) H ( P ) − H ( P ∣ Q ) H ( P ) H ( Q ) − H ( P , Q ) 信息增益 I(P,Q)H(P)−H(P∣Q)H(P)H(Q)-H(P,Q) 信息…

企业架构LNMP学习笔记10

1、Nginx版本&#xff0c;在实际的业务场景中&#xff0c;需要使用软件新版本的功能、特性。就需要对原有软件进行升级或重装系统。 Nginx的版本需要升级迭代。那么如何进行升级呢&#xff1f;线上服务器如何升级&#xff0c;我们选择稳定版本。 从nginx的1.14版本升级到ngin…

Linux系统中驱动入门设备树DTS(经典)

设备树&#xff08;DTS:device tree source&#xff09;&#xff0c;字面意思就是一块电路板上设备如上图中CPU、DDR、I2C、GPIO、SPI等&#xff0c;按照树形结构描绘成的一棵树。按照策略和功能分离的思路&#xff0c;就是驱动代码&#xff08;功能&#xff09;和设备树DTS配置…

软件测试/测试开发丨Selenium 高级控件交互方法

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27045 一、使用场景 使用场景对应事件复制粘贴键盘事件拖动元素到某个位置鼠标事件鼠标悬停鼠标事件滚动到某个元素滚动事件使用触控笔点击触控笔事件&am…

IIR滤波器

IIR滤波器原理 IIR的特点是&#xff1a;非线性相位、消耗资源少。 IIR滤波器的系统函数与差分方程如下所示&#xff1a; 由差分方程可知IIR滤波器存在反馈&#xff0c;因此在FPGA设计时要考虑到有限字长效应带来的影响。差分方程中包括两个部分&#xff1a;输入信号x(n)的M节…

Git中smart Checkout与force checkout

Git中smart Checkout与force checkout 使用git进行代码版本管理,当我们切换分支有时会遇到这样的问题&#xff1a; 这是因为在当前分支修改了代码&#xff0c;但是没有commit,所以在切换到其他分支的时候会弹出这个窗口&#xff0c; 提示你选force checkout或者smart checko…

罗勇军 →《算法竞赛·快冲300题》每日一题:“游泳” ← DFS+剪枝

【题目来源】http://oj.ecustacm.cn/problem.php?id1753http://oj.ecustacm.cn/viewnews.php?id1023【题目描述】 游泳池可以等分为n行n列的小区域&#xff0c;每个区域的温度不同。 小明现在在要从游泳池的左上角(1, 1)游到右下角(n, n)&#xff0c;小明只能向上下左右四个方…