前言

本文主要分享一下zookeeper的一些基本概念,在正式进入正题前,和大家聊一聊刚入行时我的面试经验,可以说是耿直的有些可爱。

面试官:用过zookeeper 吗?

:用过啊,给dubbo提供服务的注册与发现嘛

面试官:知道 zookeeper 是什么吗?

:知道啊,注册中心嘛

面试官:那你们项目中都是怎么用 zookeeper 的?

:就在 springboot 的 application.properties 配置文件里添加一个 zookeeper 服务地址就行了。。。


上边的对话好像也没什么毛病,但似乎又感觉哪里有点不太对,结果就是每次我如此回答面试都被pass。

为什么会被问zookeeper?因为我的简历项目上写着熟练使用zookeeper,可面试官理解的 “熟练” 使用可不是会配置,工程启动不报错那么简单。所以还是有必要全面了解一下zookeeper的相关知识。


一、zookeeper初识?

Zookeeper 它作为Hadoop项目中的一个开源子项目,是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务。

1、zookeeper数据模型

zookeeper 维护了一个类似文件系统的数据结构,每个子目录(/微信、/微信/公众号)都被称作为 znode 即节点。和文件系统一样,我们可以很轻松的对 znode 节点进行增加、删除等操作,而且还可以在一个znode下增加、删除子znode,区别在于文件系统的是,znode可以存储数据(严格说是必须存放数据,默认是个空字符)。

由于zookeeper是目录节点结构,在获取和创建节点时,必须要以“/” 开头,否则在获取节点时会报错 Path must start with / character

1[zk: localhost:2181(CONNECTED) 13] get test
2Command failed: java.lang.IllegalArgumentException: Path must start with / character

根节点名必须为“/XXX”,创建子节点时必须要带上根节点目录“/XXX/CCC”“/XXX/AAA”

例如:想要获取下图 程序员内点事 节点必须拼接完整的路径 get /微信/公众号/程序员内点事

1get /微信/公众号/程序员内点事

znode被用来存储 byte级或 kb级的数据,可存储的最大数据量是1MB请注意:一个节点的数据量不仅包含它自身存储数据,它的所有子节点的名字也要折算成Byte数计入,因此znode的子节点数也不是无限的)虽然可以手动的修改节点存储量大小,但一般情况下并不推荐这样做。

2、znode节点属性

一个znode节点不仅可以存储数据,还有一些其他特别的属性。接下来我们创建一个/test节点分析一下它各个属性的含义。

 1[zk: localhost:2181(CONNECTED) 6] get /test24563cZxid = 0x59ac //4ctime = Mon Mar 30 15:20:08 CST 20205mZxid = 0x59ad6mtime = Mon Mar 30 15:22:25 CST 20207pZxid = 0x59ac8cversion = 09dataVersion = 2
10aclVersion = 0
11ephemeralOwner = 0x0
12dataLength = 3
13numChildren = 0  

我们看到一个znode节点的属性比较多,但比较主要的属性还是zxidversionacl 这三个。


Zxid:

znode节点状态改变会导致该节点收到一个zxid格式的时间戳,这个时间戳是全局有序的,znode节点的建立或者更新都会产生一个新的。如果zxid1的值 < zxid2的值,那么说明zxid2发生的改变在zxid1之后。每个znode节点都有3个zxid属性,cZxid(节点创建时间)、mZxid(该节点修改时间,与子节点无关)、pZxid(该节点或者该节点的子节点的最后一次创建或者修改时间,孙子节点无关)。

zxid属性主要应用于zookeeper的集群,这个后边介绍集群时详细说。

Version:

znode属性中一共有三个版本号dataversion(数据版本号)、cversion(子节点版本号)、aclversion(节点所拥有的ACL权限版本号)。

znode中的数据可以有多个版本,如果某一个节点下存有多个数据版本,那么查询这个节点数据就需要带上版本号。每当我们对znode节点数据修改后,该节点的dataversion版本号会递增。当客户端请求该znode节点时,会同时返回节点数据和版本号。另外当dataversion为 -1的时候可以忽略版本进行操作。对一个节点设置权限时aclVersion版本号会递增,下边会详细说ACL权限控制。

验证一下,我们修改/test节点的数据看看dataVersion有什么变化,发现dataVersion属性变成了 3,版本号递增了。

 1[zk: localhost:2181(CONNECTED) 10] set /test 88882cZxid = 0x59ac3ctime = Mon Mar 30 15:20:08 CST 20204mZxid = 0x59b65mtime = Mon Mar 30 16:58:08 CST 20206pZxid = 0x59ac7cversion = 08dataVersion = 39aclVersion = 0
10ephemeralOwner = 0x0
11dataLength = 4
12numChildren = 0
3、znode的类型

zookeeper 有四种类型的znode,在用客户端 client 创建节点的时候需要指定类型。

1zookeeper.create("/公众号/程序员内点事", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
  • PERSISTENT-持久化目录节点 :client创建节点后,与zookeeper断开连接该节点将被持久化,当client再次连接后节点依旧存在。

  • PERSISTENT_SEQUENTIAL-持久化顺序节点 :client创建节点后,与zookeeper断开连接该节点将被持久化,再次连接节点还存在,zookeeper会给该节点名称进行顺序编号,例如:/lock/0000000001、/lock/0000000002、/lock/0000000003。

  • EPHEMERAL-临时目录节点 :client与zookeeper断开连接后,该节点即会被删除

  • EPHEMERAL_SEQUENTIAL-临时顺序节点 :client与zookeeper断开连接后,该节点被删除,会给该节点名称进行顺序编号,例如:/lock/0000000001、/lock/0000000002、/lock/0000000003。

二、节点的ACL权限控制

ACL:即 Access Control List (节点的权限控制),通过ACL机制来解决znode节点的访问权限问题,要注意的是zookeeper对权限的控制是基于znode级别的,也就说节点之间的权限不具有继承性,即子节点不继承父节点的权限。

zookeeper中设置ACL权限的格式由<schema>:<id>:<acl>三段组成。

schema :表示授权的方式

  • world:表示任何人都可以访问

  • auth:只有认证的用户可以访问

  • digest:使用username :password用户密码生成MD5哈希值作为认证ID

  • host/ip:使用客户端主机IP地址来进行认证

id:权限的作用域,用来标识身份,依赖于schema选择哪种方式。

acl:给一个节点赋予哪些权限,节点的权限有create,、delete、write、read、admin 统称 cdwra

1、world:表示任何人都可以访问

我们用 getAcl 命令来看一下,没有设置过权限的znode节点,默认情况下的权限情况。

1[zk: localhost:2181(CONNECTED) 12] getAcl /test
2'world,'anyone
3: cdrwa

看到没有设置ACL属性的节点,默认schema 使用的是world,作用域是anyone,节点权限是cdwra,也就是说任何人都可以访问。

那我们如果要给一个schema 为非world的节点设置world权限咋搞?

1setAcl /test world:anyone:crdwa
2、auth:只有认证的用户可以访问

schema 用auth授权表示只有认证后的用户才可以访问,那么首先就需要添加认证用户,添加完以后需要对认证的用户设置ACL权限。

1addauth digest test:password(明文)

需要注意的是设置认证用户时的密码是明文的。

1[zk: localhost:2181(CONNECTED) 2] addauth digest user:user //用户名:密码
2[zk: localhost:2181(CONNECTED) 5] setAcl /test auth:user:crdwa
3[zk: localhost:2181(CONNECTED) 6] getAcl /test
4'digest,'user:ben+k/3JomjGj4mfd4fYsfM6p0A=
5: cdrwa

实际上我们这样设置以后,就是将这个节点开放给所有认证的用户,setAcl /test auth:user:crdwa 相当于setAcl /test auth::crdwa

3、digest:用户名:密码的验证方式

用户名:密码方式授权是针对单个特定用户,这种方式是不需要先添加认证用户的。

如果在代码中使用zookeeper客户端设置ACL,那么密码是明文的,但若是zk.cli等客户端操作就需要将密码进行sha1base64处理。

1setAcl <path> digest:<user>:<password(密文)>:<acl>
2
3setAcl /test digest:user:jalRr+knv/6L2uXdenC93dEDNuE=:crdwa

那么密码如何加密嘞?有以下几种方式:

通过shell命令加密

1echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
2

使用zookeeper自带的类库org.apache.zookeeper.server.auth.DigestAuthenticationProvider生成

1java -cp /zookeeper-3.4.13/zookeeper-3.4.13.jar:/zookeeper-3.4.13/lib/slf4j-api-1.7.25.jar \
2  org.apache.zookeeper.server.auth.DigestAuthenticationProvider \
3  root:root
4root:root->root:qiTlqPLK7XM2ht3HMn02qRpkKIE=
4、host/ip:使用客户端主机IP地址来进行认证

这种方式就比较好理解了,通过对特定的IP地址,也可以是一个IP段进行授权。

 1[zk: localhost:2181(CONNECTED) 3] setAcl /test0000000014 ip:127.0.0.1:crdwa2cZxid = 0x59ac3ctime = Mon Mar 30 15:20:08 CST 20204mZxid = 0x59b65mtime = Mon Mar 30 16:58:08 CST 20206pZxid = 0x59ac7cversion = 08dataVersion = 39aclVersion = 3 // 这个版本一直在增加
10ephemeralOwner = 0x0
11dataLength = 4
12numChildren = 0

三、zookeeper的灵魂 watcher

我们在开头就说过:zookeeper可以为dubbo提供服务的注册与发现,作为注册中心,但你有想过zookeeper为啥能够实现服务的注册与发现吗?这就不得不说一下zookeeper的灵魂 Watcher(监听者)。

1、watcher是个啥?

watcher 是zooKeeper中一个非常核心功能 ,客户端watcher 可以监控节点的数据变化以及它子节点的变化,一旦这些状态发生变化,zooKeeper服务端就会通知所有在这个节点上设置过watcher的客户端 ,从而每个客户端都很快感知,它所监听的节点状态发生变化,而做出对应的逻辑处理。

简单的介绍了一下watcher ,那么我们来分析一下,zookeeper是如何实现服务的注册与发现。
zookeeper的服务注册与发现,主要应用的是zookeeperznode节点数据模型和watcher机制,大致的流程如下:


  • 服务注册: 服务提供者(Provider)启动时,会向zookeeper服务端注册服务信息,也就是创建一个节点,例如:用户注册服务com.xxx.user.register,并在节点上存储服务的相关数据(如服务提供者的ip地址、端口等)。

  • 服务发现: 服务消费者(Consumer)启动时,根据自身配置的依赖服务信息,向zookeeper服务端获取注册的服务信息并设置watch监听,获取到注册的服务信息之后,将服务提供者的信息缓存在本地,并进行服务的调用。

  • 服务通知: 一旦服务提供者因某种原因宕机不再提供服务之后,客户端与zookeeper服务端断开连接,zookeeper服务端上服务提供者对应服务节点会被删除(例如:用户注册服务com.xxx.user.register),随后zookeeper服务端会异步向所有消费用户注册服务com.xxx.user.register,且设置了watch监听的服务消费者发出节点被删除的通知,消费者根据收到的通知拉取最新服务列表,更新本地缓存的服务列表。

上边的过程就是zookeeper可以实现服务注册与发现的大致原理。

2、watcher类型

znode节点可以设置两类watch,一种是DataWatches,基于znode节点的数据变更从而触发 watch 事件,触发条件getData()exists()setData()、 create()

另一种是Child Watches,基于znode的孩子节点发生变更触发的watch事件,触发条件 getChildren()、 create()

而在调用 delete() 方法删除znode时,则会同时触发Data WatchesChild Watches,如果被删除的节点还有父节点,则父节点会触发一个Child Watches

3、watcher特性

watch对节点的监听事件是一次性的!客户端在指定的节点设置了监听watch,一旦该节点数据发生变更通知一次客户端后,客户端对该节点的监听事件就失效了。

如果还要继续监听这个节点,就需要我们在客户端的监听回调中,再次对节点的监听watch事件设置为True。否则客户端只能接收到一次该节点的变更通知。

四、zookeeper能实现哪些功能

服务的注册与发现功能只是zookeeper的冰山一角,它还能实现诸如分布式锁、队列、配置中心等一系列功能,接下来我们只分析一下原理,具体的实现大家上网查一下资料还是比较全的。

1、分布式锁

zookeeper基于watcher机制和znode的有序节点,天生就是一个分布式锁的坯子。首先创建一个/test/lock父节点作为一把锁,尽量是持久节点(PERSISTENT类型),每个尝试获取这把锁的客户端,在/test/lock父节点下创建临时顺序子节点。

由于序号的递增性,我们规定序号最小的节点即获得锁。例如:客户端来获取锁,在/test/lock节点下创建节点为/test/lock/seq-00000001,它是最小的所以它优先拿到了锁,其它节点等待通知再次获取锁。/test/lock/seq-00000001执行完自己的逻辑后删除节点释放锁。

那么节点/test/lock/seq-00000002想要获取锁等谁的通知呢?

这里我们让/test/lock/seq-00000002节点监听/test/lock/seq-00000001节点,一旦/test/lock/seq-00000001节点删除,则通知/test/lock/seq-00000002节点,让它再次判断自己是不是最小的节点,是则拿到锁,不是继续等通知。

以此类推/test/lock/seq-00000003节点监听/test/lock/seq-00000002节点,总是让后一个节点监听前一个节点,不用让所有节点都监听最小的节点,避免设置不必要的监听,以免造成大量无效的通知,形成“羊群效应”。

zookeeper分布式锁和redis分布式锁相比,因为大量的创建、删除节点性能上比较差,并不是很推荐。

在这里插入图片描述
2、分布式队列

zookeeper实现分布式队列也很简单,应用znode的有序节点天然的“先进先出”,后创建的节点总是最大的,出队总是拿序号最小的节点即可。

3、配置管理

现在有很多开源项目都在使用Zookeeper来维护配置,像消息队列Kafka中,就使用Zookeeper来维护broker的信息;dubbo中管理服务的配置信息。原理也是基于watcher机制,例如:创建一个/config节点存放一些配置,客户端监听这个节点,一点修改/config节点的配置信息,通知各个客户端数据变更重新拉取配置信息。

4、命名服务

zookeeper的命名服务:也就是我们常说的服务注册与发现,主要是根据指定名字来获取资源或服务的地址,服务提供者等信息,利用其znode节点的特点和watcher机制,将其作为动态注册和获取服务信息的配置中心,统一管理服务名称和其对应的服务器列表信息,我们能够近乎实时地感知到后端服务器的状态(上线、下线、宕机)。

总结

本文旨在给大家介绍一下zookeeper的基础知识,像面试中被问频率较高的zookeeper集群选主等概念,并没有放在这期来写,因为集群的内容也是比较多的,我怕篇幅太长大家没有耐心看完(其实就是有点犯懒了,哈哈哈!)

感兴趣的小伙伴可以关注一波。

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:长按订阅更多精彩▼如有收获,点个在看,诚挚感谢

你的简历写了 “熟悉” zookeeper ?那这些你会吗?相关推荐

  1. 清华毕业大牛教你涨薪5K的JVM调优骚操作是什么!如何在简历写上熟悉(精通)JVM调优,有过线上调优经验!

    就在前天的时候,马士兵老师讲了一节公开课,分享了涨薪5K的JVM调优骚操作是什么!如何在简历写上熟悉(精通)JVM调优,有过线上调优经验! 主要包含的内容如下: 1. 为什么一个百万级TPS系统会频繁 ...

  2. 面试官:看你简历写了熟悉Kafka,它为什么速度会这么快?

    前言 Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写数据是会降低性能的,因为寻址会比较消耗时间,但是实际上,Kafka的特性之一就是高吞吐率. 即使是普通的服务器,Kafka也可以轻松支 ...

  3. HR吐槽某博士程序员:简历写了12页,是不是读书读傻了

    一名公司的一名HR在互联网社区吐槽起面试的一个博士:一个博士36岁才毕业,博士读了八年,简历写了12页,起码2万字算是一堆数学符号,这种人是不是读书读傻了? 很快,这名HR的吐槽引来了各路网友的口诛笔 ...

  4. 先搞清楚这些问题,简历上再写你熟悉Java!

    原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 系列文章介绍 本文是<五分钟学Java>系列文章的一篇 本系列文章主要围绕Java程序员必须掌握的核心技能,结合我个人三年 ...

  5. 程序员还不知道简历怎么写?教你如何写简历!简历写得好,offer不会跑!

    有需要面试资料或者java学习资料的可以点我->>>>>>>> 目录 (一). 程序员简历该怎么写 1. 为什么说简历很重要? 1.1 先从面试前来说 ...

  6. 简历写了会Kafka,面试官90%会让你讲讲acks参数对消息持久化的影响

    面试大厂时,一旦简历上写了Kafka,几乎必然会被问到一个问题:说说acks参数对消息持久化的影响? 这个acks参数在kafka的使用中,是非常核心以及关键的一个参数,决定了很多东西. 所以无论是为 ...

  7. 简历写得好,工作就好找

    最近我在帮朋友的公司招人,招人的第一步是要筛选简历,在这过程中,我发现虽然能收到很多简历,但实际能通过筛选能进入到技术面试流程的简历不多,估计10份里不会超过4份能通过筛选. 如果没法通过技术面试,那 ...

  8. 简历写的好,就赢了90%的人了

    欢迎关注方志朋的博客,回复"666"获面试宝典 简历是你面试的敲门砖,简历基本属于面试流程的50%,好的简历面试官一看就能被吸引,大部分简历被扔到废纸篓,所以答应我,简历用心写,简 ...

  9. 工作简历写些什么比较好? 优秀的求职简历模板包括哪些内容

    一份优秀的求职简历模板都包括哪些内容呢?我们在工作简历模板制作的过程中,要写些什么才能吸引应聘公司的注意,在众多的面试者中脱颖而出,得到想要的工作呢?下面脚步网就来具体和大家讲一下吧. 1. 基本信息 ...

最新文章

  1. Swift 中使用 SQLite——修改和删除数据
  2. javascript中while循环、do....while与for循环的用法和区别
  3. DataGrid中,读取数据库中的图片并绑定数据列或磁盘目录中的图片,用输出流方式...
  4. 强化学习(十九) AlphaGo Zero强化学习原理
  5. JavaScript学习笔记02【基础——对象(Function、Array、Date、Math)】
  6. tried to access method com.google.common.base.Stopwatch
  7. pthread 线程退出时自动释放资源
  8. MBR的Linux分区机制启动过程,linux系统启动流程(MBR)
  9. LintCode 1671. 玩游戏(贪心、难)
  10. POJ1061:青蛙的约会——题解
  11. java 三种错误类型 区别_请列举至少三种在java语言中发生“严重错误”的情况...
  12. android签名命令行,Android系统签名位置及命令
  13. 什么转换器能将excel转换成pdf
  14. 网络图片爬虫(几个简单步骤实现网页图片的爬取,详细步骤,超详细,简单易懂)
  15. Instant及LocalDateTime等使用方法
  16. Win10要是个人,也算是鬼门关走过一遭了
  17. tao的开源代码_获取并编译TAO
  18. android 指南针不稳定,Android指南针方向不可靠(低通滤波器)
  19. 图解HTTP十一:Web 的攻击技术
  20. 冷战背景下的计算机,袁岚峰:鼓吹科技冷战,格调太低

热门文章

  1. mysql declare 赋值_sql server和mysql变量赋值的区别 以及 MySql Declare(转)
  2. vue判断离开当前页面_js监听用户进入和离开当前页面
  3. 解题报告:luogu P3916 图的遍历( 缩点 + DFS ? × 思维 + 反向建边 + DFS √ )
  4. 部署war包到阿里云liunx的tomcat时报错:zip END header not found
  5. 日期相减计算年_Excel教程:excel日期问题的小妙招
  6. python输入正整数n、求n以内能被17整除的最大正整数_求100之内自然数中最大的能被17整除的数...
  7. 我在兰亭这三年之自动化框架升级
  8. 应用程序自定义快捷键
  9. 浏览器保存密码后自动填充问题
  10. 从信息熵到Codec