优点显⽽易⻅,⼈多⼲活快,并且互为备份。但是缺点也很明显。我们可以想象⼀下,以⼀个⼩研发团队开发软件为例,假设我们有⼀个
5
⼈的项⽬组,要开始⼀个系统的开发,项⽬组将⾯临如下问题:
图中列举的就是项⽬组将要⾯临到的问题,这些问题在我们⽇常⼯作中也是天天发⽣,并没感觉有多么复杂,但是这是因为我们⼈类的⼤脑是个超级计算机,能够灵活应对这些问题,⽽且现实中信息的交换
不依赖⽹络,不会因⽹络延迟或者中断,出现信息不对等,⽽且现实中对以上问题的处理其实并不严
谨,从⽽也引发了很多问题。想⼀想,项⽬中是不是出现过沟通不畅造成任务分配有歧义?是否由于⼈
员离职造成任务进⾏不下去,甚⾄要联系离职⼈员协助?是不是出现过任务分配不合理?类似这样的各
种问题,肯定会发⽣于你的项⽬组中。在现实世界,我们可以⼈为去协调,即使出错了,⼈⼯去补错,
加加班搞定就好。但在计算机的世界,这样做是⾏不通的,⼀切都要保证严谨,以上问题要做到尽可能
不要发⽣。因此,分布式系统必须采⽤合理的⽅式解决掉以上的问题。
实际上要想解决这些问题并没有那么复杂,我们仅需要做⼀件事就可以万事⽆忧
---
让信息在项⽬组成员中同步。如果能做到信息同步,那么每个⼈在⼲什么,⼤家都是清楚的,⼲到什么程度也是清晰的,⽆
论谁离职也不会产⽣问题。分配的⼯作,能够及时清晰的同步给每个组员,确保每个组员收到的任务分
配没有冲突。
分布式系统的协调⼯作就是通过某种⽅式,让每个节点的信息能够同步和共享。这依赖于服务进程之间的通信。通信⽅式有两种:
这就像现实中,开发
leader
在会上把任务传达下去,组员通过听
leader
命令或者看
leader
的邮件知道⾃⼰要⼲什么。当任务分配有变化时,
leader
会单ᇿ告诉组员,或者再次召开会议。信息通过⼈与⼈之间
的直接沟通,完成传递。
这就好⽐开发
leader
按照约定的时间和路径,把任务分配表放到了
svn
上,组员每天去
svn
上拉取最新的任务分配表,然后⼲活。其中
svn
就是共享存储。更好⼀点的做法是,当
svn
⽂件版本更新时,触发邮件
通知,每个组员再去拉取最新的任务分配表。这样做更好,因为每次更新,组员都能第⼀时间得到消
息,从⽽让⾃⼰⼿中的任务分配表永远是最新的。此种⽅式依赖于中央存储。整个过程如下图所示:
ZooKeeper如何解决分布式系统⾯临的问题
ZooKeeper
对分布式系统的协调,使⽤的是第⼆种⽅式,共享存储。其实共享存储,分布式应⽤也需要和存储进⾏⽹络通信。
实际上,通过
ZooKeeper
实现分布式协同的原理,和项⽬组通过
SVN
同步⼯作任务的例⼦是⼀样的。ZooKeeper
就像是
svn
,存储了任务的分配、完成情况等共享信息。每个分布式应⽤的节点就是组员,
订阅这些共享信息。当主节点(组
leader
),对某个从节点的分⼯信息作出改变时,相关订阅的从节点
得到
zookeeper
的通知,取得⾃⼰最新的任务分配。完成⼯作后,把完成情况存储到
zookeeper
。主节
点订阅了该任务的完成情况信息,所以将得到
zookeeper
的完⼯的通知。参考下图,是不是和前⾯项⽬
组通过
svn
分配⼯作的例⼦⼀模⼀样?仅仅是把
svn
和邮件系统合⼆为⼀,以
ZooKeeper
代替。
注:
Slave
节点要想获取
ZooKeeper
的更新通知,需事先在关⼼的数据节点上设置观察点。
⼤多数分布式系统中出现的问题,都源于信息的共享出了问题。如果各个节点间信息不能及时共享和同步,那么就会在协作过程中产⽣各种问题。
ZooKeeper
解决协同问题的关键,就是在于保证分布式系统
信息的⼀致性。
(二)zookeeper的基本概念
Zookeeper
是⼀个开源的分布式协调服务,其设计⽬标是将那些复杂的且容易出错的分布式⼀致性服务封装起来,构成⼀个⾼效可靠的原语集,并以⼀些简单的接⼝提供给⽤户使⽤。
zookeeper
是⼀个典型
的分布式数据⼀致性的解决⽅案,分布式应⽤程序可以基于它实现诸如数据订阅
/
发布、负载均衡、命名
服务、集群管理、分布式锁和分布式队列等功能。
基本概念:
①
集群⻆⾊
通常在分布式系统中,构成⼀个集群的每⼀台机器都有⾃⼰的⻆⾊,最典型的集群就是
Master/Slave
模式(主备模式),此情况下把所有能够处理写操作的机器称为
Master
机器,把所有通过异步复制⽅式获
取最新数据,并提供读服务的机器为
Slave
机器。
⽽在
Zookeeper
中,这些概念被颠覆了。它没有沿⽤传递的
Master/Slave
概念,⽽是引⼊了
Leader
、Follower
、
Observer
三种⻆⾊。
Zookeeper
集群中的所有机器通过
Leader
选举来选定⼀台被称为
Leader
的机器,
Leader
服务器为客户端提供读和写服务,除
Leader
外,其他机器包括
Follower
和
Observer,Follower
和
Observer
都能提供读服务,唯⼀的区别在于
Observer
不参与
Leader
选举过程
,
不参与写操作
的
过半写成功
策略,因此
Observer
可以在不影响写性能的情况下提升集群的性能。
②
会话(
session
)
Session
指客户端会话,
⼀个客户端连接是指客户端和服务端之间的⼀个
TCP
⻓连接
,
Zookeeper
对外的服务端⼝默认为
2181
,客户端启动的时候,⾸先会与服务器建⽴⼀个
TCP
连接,从第⼀次连接建⽴开
始,客户端会话的⽣命周期也开始了,通过这个连接,客户端能够⼼跳检测与服务器保持有效的会话,
也能够向
Zookeeper
服务器发送请求并接受响应,同时还能够通过该连接接受来⾃服务器的
Watch
事件
通知。
③
数据节点(
Znode
)
在谈到分布式的时候,我们通常说的
“
节点
”
是指组成集群的每⼀台机器。然⽽,在
ZooKeeper
中,
“
节点
”
分为两类,第⼀类同样是指构成集群的机器,我们称之为
机器节点
;第⼆类则是指数据模型中的
数据
单元
,我们称之为数据节点
——ZNode
。
ZooKeeper
将所有数据存储在内存中,数据模型是⼀棵树
(
ZNode Tree
),由斜杠(
/
)进⾏分割的路径,就是⼀个
Znode
,例如
/app/path1
。每个
ZNode
上都
会保存⾃⼰的数据内容,同时还会保存⼀系列属性信息。
④
版本
刚刚我们提到,
Zookeeper
的每个
Znode
上都会存储数据,对于每个
ZNode
,
Zookeeper
都会为其维护⼀个叫作
Stat
的数据结构,
Stat
记录了这个
ZNode
的三个数据版本,分别是
version
(当前
ZNode
的版
本)、
cversion
(当前
ZNode
⼦节点的版本)、
aversion
(当前
ZNode
的
ACL
版本)。
⑤
Watcher
(事件监听器)
Wathcer
(事件监听器),是
Zookeeper
中⼀个很重要的特性,
Zookeeper
允许⽤户在指定节点上注册⼀些
Watcher
,并且在⼀些特定事件触发的时候,
Zookeeper
服务端会将事件通知到感兴趣的客户端,
该机制是
Zookeeper
实现分布式协调服务的重要特性
⑥
ACL
Zookeeper
采⽤
ACL
(
Access Control Lists
)策略来进⾏权限控制,其定义了如下五种权限:
· CREATE
:创建⼦节点的权限。
· READ
:获取节点数据和⼦节点列表的权限。
· WRITE
:更新节点数据的权限。
· DELETE
:删除⼦节点的权限。
· ADMIN
:设置节点
ACL
的权限。
其中需要注意的是,
CREATE
和
DELETE
这两种权限都是针对⼦节点的权限控制。
二. Zookeeper环境搭建
(一)单机模式
Zookeeper只运⾏在⼀台服务器上,适合测试环境;
Zookeeper本地模式安装_舞鹤白沙编码日志-CSDN博客_zookeeper本地模式安装
(二)伪集群模式:
Zookeeper
不但可以在单机上运⾏单机模式
Zookeeper
,⽽且可以在单机模拟集群模式
Zookeeper
的运⾏,也就是将不同实例运⾏在同⼀台机器,⽤端⼝进⾏区分,伪集群模式为我们体验
Zookeeper
和做⼀
些尝试性的实验提供了很⼤的便利。⽐如,我们在测试的时候,可以先使⽤少量数据在伪集群模式下进
⾏测试。当测试可⾏的时候,再将数据移植到集群模式进⾏真实的数据实验。这样不但保证了它的可⾏
性,同时⼤⼤提⾼了实验的效率。这种搭建⽅式,⽐较简便,成本⽐较低,适合测试和学习。
注意事项:
⼀台机器上部署了
3
个
server
,也就是说单台机器及上运⾏多个
Zookeeper
实例。这种情况下,必须保证每个配置⽂档的各个端⼝号不能冲突,除
clientPort
不同之外,
dataDir
也不同。另外,还要在
dataDir
所对应的⽬录中创建
myid
⽂件来指定对应的
Zookeeper
服务器实例:
如果在
1
台机器上部署多个
server
,那么每台机器都要不同的
clientPort
,⽐如
server1
是
2181,server2是
2182
,
server3
是
2183
dataDir
和
dataLogDir
也需要区分下,将数据⽂件和⽇志⽂件分开存放,同时每个
server
的这两变量所对应的路径都是不同的
server.X
这个数字就是对应,
data/myid
中的数字。在
3
个
server
的
myid
⽂件中分别写⼊了
1
,
2
,
3
,那么每个
server
中的
zoo.cfg
都配
server.1 server.2,server.3
就⾏了。因为在同⼀台机器上,后⾯连着的
2
个端⼝,
3
个
server
都不要⼀样,否则端⼝冲突
将
zookeeper
压缩包
zookeeper-3.4.14.tar.gz
上传到
linux
系统
解压 压缩包
创建⽬录
zkcluster
mkdir zkcluster
解压
zookeeper-3.4.14.tar.gz
到
zkcluster
⽬录下
tar -zxvf zookeeper-3.4.14.tar.gz -C /zkcluster
改变名称
mv zookeeper-3.4.14 zookeeper01
复制并改名
cp -r zookeeper01/ zookeeper02
cp -r zookeeper01/ zookeeper03
分别在
zookeeper01
、
zookeeper02
、
zookeeper03
⽬录下创建
data
及
logs
⽬录
mkdir data
cd data
mkdir logs
修改配置⽂件名称
cd conf
mv zoo_sample.cfg zoo.cfg
配置每⼀个
Zookeeper
的
dataDir
(
zoo.cfg
)
clientPort
分别为
2181 2182 2183
clientPort=2181
dataDir=/zkcluster/zookeeper01/data
dataLogDir=/zkcluster/zookeeper01/data/logs
clientPort=2182
dataDir=/zkcluster/zookeeper02/data
dataLogDir=/zkcluster/zookeeper02/data/logs
clientPort=2183
dataDir=/zkcluster/zookeeper03/data
dataLogDir=/zkcluster/zookeeper03/data/logs
配置集群
(1
)在每个
zookeeper
的
data
⽬录下创建⼀个
myid
⽂件,内容分别是
1
、
2
、
3
。这个⽂件就是记录
每个服务器的
ID
touch myid
(2
)在每⼀个
zookeeper
的
zoo.cfg
配置客户端访问端⼝(
clientPort
)和集群服务器
IP
列表。
server.1=10.211.55.4:2881:3881
server.2=10.211.55.4:2882:3882
server.3=10.211.55.4:2883:3883
#server.
服务器
ID=
服务器
IP
地址:服务器之间通信端⼝:服务器之间投票选举端⼝
(三)集群模式:
三. Zookeeper基本使⽤
(一)ZooKeeper系统模型
1. ZooKeeper数据模型Znode
在
ZooKeeper
中,数据信息被保存在⼀个个数据节点上,这些节点被称为
znode
。
ZNode
是
Zookeeper
中最⼩数据单位,在
ZNode
下⾯⼜可以再挂
ZNode
,这样⼀层层下去就形成了⼀个层次化命名空间
ZNode
树,我们称为
ZNode Tree
,它采⽤了类似⽂件系统的层级树状结构进⾏管理。⻅下图
示例:
在
Zookeeper
中,每⼀个数据节点都是⼀个
ZNode
,上图根⽬录下有两个节点,分别是:
app1
和
app2
,其中
app1
下⾯⼜有三个⼦节点
,
所有
ZNode
按层次化进⾏组织,形成这么⼀颗树,
ZNode
的节点路径标识⽅式和
Unix
⽂件系统路径⾮常相似,都是由⼀系列使⽤斜杠(
/
)进⾏分割的路径表示,开发⼈员可以向这个节点写⼊数据,也可以在这个节点下⾯创建⼦节点。
2. ZNode 的类型
刚刚已经了解到,
Zookeeper
的
znode tree
是由⼀系列数据节点组成的,那接下来,我们就对数据节点做详细讲解
Zookeeper
节点类型可以分为三⼤类:
- 持久性节点(Persistent)
- 临时性节点(Ephemeral)
- 顺序性节点(Sequential)
在开发中在创建节点的时候通过组合可以⽣成以下四种节点类型:持久节点、持久顺序节点、临时节点、临时顺序节点。不同类型的节点则会有不同的⽣命周期。
持久节点:
是
Zookeeper
中最常⻅的⼀种节点类型,所谓持久节点,就是指节点被创建后会⼀直存在服务器,直到删除操作主动清除
持久顺序节点:
就是有顺序的持久节点,节点特性和持久节点是⼀样的,只是额外特性表现在顺序上。顺序特性实质是在创建节点的时候,会在节点名后⾯加上⼀个数字后缀,来表示其顺序。
临时节点:
就是会被⾃动清理掉的节点,它的⽣命周期和客户端会话绑在⼀起,客户端会话结束,节点会被删除掉。与持久性节点不同的是,临时节点不能创建⼦节点。
临时顺序节点:
就是有顺序的临时节点,和持久顺序节点相同,在其创建的时候会在名字后⾯加上数字后缀。
3. 事务ID
⾸先,先了解,事务是对物理和抽象的应⽤状态上的操作集合。往往在现在的概念中,ሀ义上的事务通常指的是数据库事务,⼀般包含了⼀系列对数据库有序的读写操作,这些数据库事务具有所谓的
ACID
特
性,即原⼦性(
Atomic
)、⼀致性(
Consistency
)、隔离性(
Isolation
)和持久性
(
Durability
)。
⽽在
ZooKeeper
中,事务是指能够改变
ZooKeeper
服务器状态的操作,我们也称之为事务操作或更新操作,⼀般包括数据节点创建与删除、数据节点内容更新等操作。对于每⼀个事务请求,
ZooKeeper
都会
为其分配⼀个全局唯⼀的事务
ID
,⽤
ZXID
来表示,通常是⼀个
64
位的数字。每⼀个
ZXID
对应⼀次更
新操作,从这些
ZXID
中可以间接地识别出
ZooKeeper
处理这些更新操作请求的全局顺序
4. ZNode 的状态信息

整个
ZNode
节点内容包括两部分:节点数据内容和节点状态信息。图中
quota
是数据内容,其他的属于状态信息。那么这些状态信息都有什么含义呢?
- cZxid 就是 Create ZXID,表示节点被创建时的事务ID。
- ctime 就是 Create Time,表示节点创建时间。
- mZxid 就是 Modified ZXID,表示节点最后⼀次被修改时的事务ID。
- mtime 就是 Modified Time,表示节点最后⼀次被修改的时间。
- pZxid 表示该节点的⼦节点列表最后⼀次被修改时的事务 ID。只有⼦节点列表变更才会更新 pZxid,⼦节点内容变更不会更新。
- cversion 表示⼦节点的版本号。
- dataVersion 表示内容版本号。
- aclVersion 标识acl版本
- ephemeralOwner 表示创建该临时节点时的会话 sessionID,如果是持久性节点那么值为 0
- dataLength 表示数据⻓度。
- numChildren 表示直系⼦节点数。
5. Watcher--数据变更通知
Zookeeper
使⽤
Watcher
机制实现分布式数据的发布
/
订阅功能
⼀个典型的发布
/
订阅模型系统定义了⼀种 ⼀对多的订阅关系,能够让多个订阅者同时监听某⼀个主题对象,当这个主题对象⾃身状态变化时,会通知所有订阅者,使它们能够做出相应的处理。
在
ZooKeeper
中,引⼊了
Watcher
机制来实现这种分布式的通知功能。
ZooKeeper
允许客户端向服务端注册⼀个
Watcher
监听,当服务端的⼀些指定事件触发了这个
Watcher
,那么就会向指定客户端发
送⼀个事件通知来实现分布式的通知功能。
Zookeeper
的
Watcher
机制主要包括
客户端线程、客户端
WatcherManager
、
Zookeeper
服务器
三部分。
具体⼯作流程为:客户端在向
Zookeeper
服务器注册的同时,会将
Watcher
对象存储在客户端的
WatcherManager
当中。当
Zookeeper
服务器触发
Watcher
事件后,会向客户端发送通知,客户端线程从
WatcherManager
中取出对应的
Watcher
对象来执⾏回调逻辑。
6. ACL--保障数据的安全
Zookeeper
作为⼀个分布式协调框架,其内部存储了分布式系统运⾏时状态的元数据,这些元数据会直接影响基于
Zookeeper
进⾏构造的分布式系统的运⾏状态,因此,如何保障系统中数据的安全,从⽽避
免因误操作所带来的数据随意变更⽽导致的数据库异常⼗分重要,在
Zookeeper
中,提供了⼀套完善的
ACL
(
Access Control List
)权限控制机制来保障数据的安全。
我们可以从三个⽅⾯来理解
ACL
机制:
权限模式(
Scheme
)、授权对象(
ID
)、权限
(
Permission
)
,通常使⽤
"
scheme: id : permission
"
来标识⼀个有效的
ACL
信息。
7. 权限模式:Scheme
权限模式⽤来确定权限验证过程中使⽤的检验策略,有如下四种模式:
(1)IP
IP
模式就是通过
IP
地址粒度来进⾏权限控制,如
"ip:192.168.0.110"
表示权限控制针对该
IP
地址,
同时
IP
模式可以⽀持按照⽹段⽅式进⾏配置,如
"ip:192.168.0.1/24"
表示针对
192.168.0.*
这个⽹段
进⾏权限控制。
(2)Digest
Digest
是最常⽤的权限控制模式,要更符合我们对权限控制的认识,其使
⽤
"username:password"
形式的权限标识来进⾏权限配置,便于区分不同应⽤来进⾏权限控制。
当我们通过
“username:password”
形式配置了权限标识后,
Zookeeper
会先后对其进⾏
SHA-1
加密
和
BASE64
编码。
(3) World
World
是⼀种最开放的权限控制模式,这种权限控制⽅式⼏乎没有任何作⽤,数据节点的访问权限
对所有⽤户开放,即所有⽤户都可以在不进⾏任何权限校验的情况下操作
ZooKeeper
上的数据。
另外,
World
模式也可以看作是⼀种特殊的
Digest
模式,它只有⼀个权限标识,即
“world
:
anyone”
。
(4) Super
Super
模式,顾名思义就是超级⽤户的意思,也是⼀种特殊的
Digest
模式。在
Super
模式下,超级
⽤户可以对任意
ZooKeeper
上的数据节点进⾏任何操作。
8. 授权对象:ID
授权对象指的是权限赋予的⽤户或⼀个指定实体,例如
IP
地址或是机器等。在不同的权限模式下,授权对象是不同的,表中列出了各个权限模式和授权对象之间的对应关系。
权限
权限就是指那些通过权限检查后可以被允许执⾏的操作。在
ZooKeeper
中,所有对数据的操作权限分为以下五⼤类:
· CREATE
(C
):数据节点的创建权限,允许授权对象在该数据节点下创建⼦节点。
· DELETE
(
D
):
⼦节点的删除权限,允许授权对象删除该数据节点的⼦节点。
· READ
(
R
):数据节点的读取权限,允许授权对象访问该数据节点并读取其数据内容或⼦节点列表等。
· WRITE
(
W
):数据节点的更新权
限,允许授权对象对该数据节点进⾏更新操作。
· ADMIN
(
A
):数据节点的管理权限,允许授权对象对该数据节点进⾏
ACL
相关的设置操作。
(二)ZooKeeper命令⾏操作
现在已经搭建起了⼀个能够正常运⾏的
zookeeper
服务了,所以接下来,就是来借助客户端来对
zookeeper
的数据节点进⾏操作
⾸先,进⼊到
zookeeper
的
bin
⽬录之后
通过
zkClient
进⼊
zookeeper
客户端命令⾏
./zkcli.sh
连接本地的
zookeeper
服务器
./zkCli.sh -server ip:port
连接指定的服务器
连接成功之后,系统会输出
Zookeeper
的相关环境及配置信息等信息。输⼊
help
之后,屏幕会输出可⽤的
Zookeeper
命令,如下图所示
1. 创建节点
使⽤create命令,可以创建⼀个Zookeeper节点, 如
create [-s][-e] path data acl
其中,
-s
或
-e
分别指定节点特性,顺序或临时节点,若不指定,则创建持久节点;
acl
⽤来进⾏权限控制。
① 创建顺序节点
使⽤
create -s /zk-test 123
命令创建
zk-test
顺序节点
执⾏完后,就在根节点下创建了⼀个叫做
/zk-test
的节点,该节点内容就是
123
,同时可以看到创建的zk-test
节点后⾯添加了⼀串数字以示区别
② 创建临时节点
使⽤
create -e /zk-temp 123
命令创建
zk-temp
临时节
临时节点在客户端会话结束后,就会⾃动删除,下⾯使⽤
quit
命令退出客户端
再次使⽤客户端连接服务端,并使⽤
ls /
命令查看根⽬录下的节点
可以看到根⽬录下已经不存在
zk-temp
临时节点了
③ 创建永久节点
使⽤
create /zk-permanent 123
命令创建
zk-permanent
永久节点
可以看到根⽬录下已经不存在
zk-temp
临时节点了
③ 创建永久节点
使⽤
create /zk-permanent 123
命令创建
zk-permanent
永久节点
可以看到永久节点不同于顺序节点,不会⾃动在后⾯添加⼀串数字
2. 读取节点
与读取相关的命令有
ls
命令和
get
命令
ls命令可以列出Zookeeper指定节点下的所有⼦节点,但只能查看指定节点下的第⼀级的所有⼦节点;
ls path
其中,
path
表示的是指定数据节点的节点路径
get
命令可以获取
Zookeeper
指定节点的数据内容和属性信息。
get path
也可以用ls2 path,两者区别是get会显示节点内的数据内容,ls2则不显示数据内容
若获取根节点下⾯的所有⼦节点,使⽤
ls /
命令即可
若想获取
/zk-permanent
的数据内容和属性,可使⽤如下命令:
get /zk-permanent
从上⾯的输出信息中,我们可以看到,第⼀⾏是节点
/zk-permanent
的数据内容,其他⼏⾏则是创建该节点的事务
ID
(
cZxid
)、最后⼀次更新该节点的事务
ID
(
mZxid
)和最后⼀次更新该节点的时间
(
mtime
)等属性信息
3. 更新节点
使⽤set命令,可以更新指定节点的数据内容,⽤法如下
set path data [version]
其中,
data
就是要更新的新内容,
version
表示数据版本,在
zookeeper
中,节点的数据是有版本概
念的,这个参数⽤于指定本次更新操作是基于
Znode
的哪⼀个数据版本进⾏的,如将
/zk-permanent
节点的数据更新为
456
,可以使⽤如下命令:
set /zk-permanent 456
现在dataVersion已经变为1了,表示进⾏了更新
4. 删除节点
使⽤delete命令可以删除Zookeeper上的指定节点,⽤法如下
delete path [version]
其中version也是表示数据版本,使⽤delete /zk-permanent 命令即可删除/zk-permanent节点
可以看到,已经成功删除
/zk-permanent
节点。值得注意的是,
若删除节点存在⼦节点,那么⽆法删除该节点,必须先删除⼦节点,再删除⽗节点
(三)Zookeeper的api使⽤
Zookeeper
作为⼀个分布式框架,主要⽤来解决分布式⼀致性问题,它提供了简单的分布式原语,并且对多种编程语⾔提供了
API
,所以接下来重点来看下
Zookeeper
的
java
客户端
API
使⽤⽅式
Zookeeper API
共包含五个包,分别为:
(1
)
org.apache.zookeeper
(2
)
org.apache.zookeeper.data
(3
)
org.apache.zookeeper.server
(4
)
org.apache.zookeeper.server.quorum
(5
)
org.apache.zookeeper.server.upgrade
其中
org.apache.zookeeper
,包含
Zookeeper
类,他是我们编程时最常⽤的类⽂件。这个类是
Zookeeper
客户端的主要类⽂件。如果要使⽤
Zookeeper
服务,应⽤程序⾸先必须创建⼀个
Zookeeper实例,这时就需要使⽤此类。⼀旦客户端和
Zookeeper
服务端建⽴起了连接,
Zookeeper
系统将会给本
次连接会话分配⼀个
ID
值,并且客户端将会周期性的向服务器端发送⼼跳来维持会话连接。只要连接有
效,客户端就可以使⽤
Zookeeper API
来做相应处理了。
准备⼯作:导⼊依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.0</version>
</dependency>
api操作Zookeeper完整代码演示(请点击)
(四)Zookeeper-开源客户端
1. ZkClient
ZkClient
是
Github
上⼀个开源的
zookeeper
客户端,在
Zookeeper
原⽣
API
接⼝之上进⾏了包装,是⼀个更易⽤的
Zookeeper
客户端,同时,
zkClient
在内部还实现了诸如
Session
超时重连、
Watcher
反复注册
等功能
接下来,还是从创建会话、创建节点、读取数据、更新数据、删除节点等⽅⾯来介绍如何使⽤
zkClient这个
zookeeper
客户端
添加依赖:
在pom.xml⽂件中添加如下内容
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.2</version>
</dependency>
ZkClient操作Zookeeper完整代码演示(请点击)
2. Curator客户端
curator
是
Netflflix
公司开源的⼀套
Zookeeper
客户端框架,和
ZKClient
⼀样,
Curator
解决了很多
Zookeeper
客户端⾮常底层的细节开发⼯作,包括连接重连,反复注册
Watcher
和
NodeExistsException
异常等,是最流⾏的
Zookeeper
客户端之⼀。从编码⻛格上来讲,它提供了基于Fluent
的编程⻛格⽀持
添加依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
创建会话
Curator
的创建会话⽅式与原⽣的
API
和
ZkClient
的创建⽅式区别很⼤。
Curator
创建客户端是通过
CuratorFrameworkFactory
⼯⼚类来实现的。具体如下:
(1)
使⽤
CuratorFramework
这个⼯⼚类的两个静态⽅法来创建⼀个客户端
public static
CuratorFramework
newClient
(
String
connectString
,
RetryPolicy
retryPolicy
)
public static
CuratorFramework
newClient
(
String
connectString
,
int
sessionTimeoutMs
,
int
connectionTimeoutMs
,
RetryPolicy retryPolicy
)
其中参数
RetryPolicy
提供重试策略的接⼝,可以让⽤户实现⾃定义的重试策略,默认提供了以下实现,分别为
ExponentialBackoffffRetry
(基于
backoffff
的重连策略)、
RetryNTimes
(重连
N
次策略)、
RetryForever
(永远重试策略)
(2)
通过调⽤
CuratorFramework
中的
start()
⽅法来启动会话
RetryPolicy retryPolicy
=
new
ExponentialBackoffRetry
(
1000
,
3
);
CuratorFramework client
=
CuratorFrameworkFactory
.
newClient
(
"127.0.0.1:2181"
,
retryPolicy
);
client
.
start
();
RetryPolicy retryPolicy
=
new
ExponentialBackoffRetry
(
1000
,
3
);
CuratorFramework client
=
CuratorFrameworkFactory
.
newClient
(
"127.0.0.1:2181"
,
5000
,
1000
,
retryPolicy
);
client
.
start
();
其实进⼀步查看源代码可以得知,其实这两种⽅法内部实现⼀样,只是对外包装成不同的⽅法。它们的底层都是通过第三个⽅法
builder
来实现的
RetryPolicy retryPolicy
=
new
ExponentialBackoffRetry
(
1000
,
3
);
private static
CuratorFramework Client
=
CuratorFrameworkFactory
.
builder
()
.
connectString
(
"server1:2181,server2:2181,server3:2181"
)
.
sessionTimeoutMs
(
50000
)
.
connectionTimeoutMs
(
30000
)
.
retryPolicy
(
retryPolicy
)
.
build
();
client
.
start
();
- connectString:zk的server地址,多个server之间使⽤英⽂逗号分隔开
- connectionTimeoutMs:连接超时时间,如上是30s,默认是15s
- sessionTimeoutMs:会话超时时间,如上是50s,默认是60s
- retryPolicy:失败重试策略
- ExponentialBackoffffRetry:构造器含有三个参数 ExponentialBackoffffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs)
- baseSleepTimeMs:初始的sleep时间,⽤于计算之后的每次重试的sleep时间,
- 计算公式:当前sleep时间=baseSleepTimeMs*Math.max(1, random.nextInt(1<<(retryCount+1)))
- maxRetries:最⼤重试次数
- maxSleepMs:最⼤sleep时间,如果上述的当前sleep计算出来⽐这个⼤,那么sleep⽤ 这个时间,默认的最⼤时间是Integer.MAX_VALUE毫秒。
- 其他,查看org.apache.curator.RetryPolicy接⼝的实现类
- start():完成会话的创建
package com.lagou.curator;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class CreateSession {
// 创建会话
public static void main(String[] args) {
//不使用fluent编程风格
RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("192.168.200.128:2181", exponentialBackoffRetry);
curatorFramework.start();
System.out.println( "会话被建立了");
// 使用fluent编程风格
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("192.168.200.128:2181") //server地址
.sessionTimeoutMs(50000) // 会话超时时间
.connectionTimeoutMs(30000) // 连接超时时间
.retryPolicy(exponentialBackoffRetry) // 重试策略
.namespace("base") // 独立的命名空间: /base
.build();
client.start();
System.out.println("会话2创建了");
}
}
需要注意的是
session2
会话含有隔离命名空间,即客户端对
Zookeeper
上数据节点的任何操作都是相对
/base
⽬录进⾏的,这有利于实现不同的
Zookeeper
的业务之间的隔离