文本已收录至我的GitHub仓库,欢迎Star: https://github.com/ZhongFuCheng3y/3y
上次写了一篇 什么是消息队列? 以后,本来想入门一下Kafka的(装一下环境、看看Kafka一些概念啥的)。后来发现Kafka用到了ZooKeeper,而我又对ZooKeeper不了解,所以想先来学学什么是ZooKeeper,再去看看什么是Kafka。
ZooKeeper相信大家已经听过这个词了,不知道大家对他了解多少呢?我第一次听到ZooKeeper的时候是在学Eureka的时候( 外行人都能看懂的SpringCloud,错过了血亏! ),同样ZooKeeper也可以作为 注册中心 。
后面听到ZooKeeper的时候,是因为ZooKeeper可以作为 分布式锁 的一种实现。
直至在了解Kafka的时候,发现Kafka也需要依赖ZooKeeper。Kafka使用ZooKeeper 管理自己的元数据配置 。
这篇文章来写写我学习ZooKeeper的笔记,如果有错的地方希望大家可以在评论区指出。
从上面我们也可以发现,好像哪都有ZooKeeper的身影,那什么是ZooKeeper呢?我们先去 官网 看看介绍:
官网还有另一段话:
ZooKeeper: A Distributed Coordination Service for Distributed Applications
相比于官网的介绍,我其实更喜欢 Wiki 中对ZooKeeper的介绍:
(留下不懂英语的泪水)
我简单概括一下:
从上面我们可以知道,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理。
统一配置管理、统一命名服务、分布式锁、集群管理 每个具体的含义(后面会讲) 那为什么ZooKeeper可以干那么多事?来看看ZooKeeper究竟是何方神物,在Wiki中其实也有提到:
ZooKeeper nodes store their data in a hierarchical name space, much like a file system or a tree ) data structure
ZooKeeper的数据结构,跟Unix文件系统非常类似,可以看做是一颗 树 ,每个节点叫做 ZNode 。每一个节点可以通过 路径 来标识,结构图如下:
那ZooKeeper这颗"树"有什么特点呢??ZooKeeper的节点我们称之为 Znode ,Znode分为 两种 类型:
ZooKeeper和Redis一样,也是C/S结构(分成客户端和服务端)
在上面我们已经简单知道了ZooKeeper的数据结构了,ZooKeeper还配合了 监听器 才能够做那么多事的。
常见的监听场景有以下两项:
没错,通过 监听+Znode节点(持久/短暂[临时]) ,ZooKeeper就可以玩出这么多花样了。
下面我们来看看用ZooKeeper怎么来做:统一配置管理、统一命名服务、分布式锁、集群管理。
比如我们现在有三个系统A、B、C,他们有三份配置,分别是 ASystem.yml、BSystem.yml、CSystem.yml ,然后,这三份配置又非常类似,很多的配置项几乎都一样。
于是,我们希望把 ASystem.yml、BSystem.yml、CSystem.yml 相同的配置项抽取出来成一份 公用 的配置 common.yml ,并且即便 common.yml 改了,也不需要系统A、B、C重启。
做法:我们可以将 common.yml 这份配置放在ZooKeeper的Znode节点中,系统A、B、C监听着这个Znode节点有无变更,如果变更了, 及时 响应。
参考资料:
基于zookeeper实现统一配置管理
统一命名服务的理解其实跟 域名 一样,是我们为这某一部分的资源给它 取一个名字 ,别人通过这个名字就可以拿到对应的资源。
比如说,现在我有一个域名 www.java3y.com ,但我这个域名下有多台机器:
别人访问 www.java3y.com 即可访问到我的机器,而不是通过IP去访问。
锁的概念在这我就不说了,如果对锁概念还不太了解的同学,可参考下面的文章
我们可以使用ZooKeeper来实现分布式锁,那是怎么做的呢??下面来看看:
系统A、B、C都去访问 /locks 节点
访问的时候会创建 带顺序号的临时/短暂 ( EPHEMERAL_SEQUENTIAL )节点,比如,系统A创建了 id_000000 节点,系统B创建了 id_000002 节点,系统C创建了 id_000001 节点。
接着,拿到 /locks 节点下的所有子节点(id_000000,id_000001,id_000002), 判断自己创建的是不是最小的那个节点
如果是,则拿到锁。
举个例子:
/locks 节点下的所有子节点,经过比较,发现自己( id_000000 ),是所有子节点最小的。所以得到锁 /locks 节点下的所有子节点,经过比较,发现自己( id_000002 ),不是所有子节点最小的。所以监听比自己小1的节点 id_000001 的状态 /locks 节点下的所有子节点,经过比较,发现自己( id_000001 ),不是所有子节点最小的。所以监听比自己小1的节点 id_000000 的状态 id_000000 )。通过监听,系统C发现 id_000000 节点已经删除了,发现自己已经是最小的节点了,于是顺利拿到锁 经过上面几个例子,我相信大家也很容易想到ZooKeeper是怎么" 感知 "节点的动态新增或者删除的了。
还是以我们三个系统A、B、C为例,在ZooKeeper中创建 临时节点 即可:
只要系统A挂了,那 /groupMember/A 这个节点就会删除,通过 监听 groupMember 下的子节点,系统B和C就能够感知到系统A已经挂了。(新增也是同理)
除了能够感知节点的上下线变化,ZooKeeper还可以实现 动态选举Master 的功能。(如果集群是主从架构模式下)
原理也很简单,如果想要实现动态选举Master的功能,Znode节点的类型是带 顺序号的临时节点 ( EPHEMERAL_SEQUENTIAL )就好了。
这篇文章主要讲解了ZooKeeper的入门相关的知识,ZooKeeper通过 Znode的节点类型+监听机制 就实现那么多好用的功能了!
当然了,ZooKeeper要考虑的事没那么简单的,后面有机会深入的话,我还会继续分享,希望这篇文章对大家有所帮助~
参考资料:
分布式服务框架 Zookeeper
ZooKeeper初识整理(老酒装新瓶)
ZooKeeper
ZooKeeper 的应用场景
乐于输出 干货 的Java技术公众号:Java3y。公众号内有200多篇 原创 技术文章、海量视频资源、精美脑图,不妨来 关注 一下!
觉得我的文章写得不错,不妨点一下 赞 !
大谢
写的不错
优秀