1_客户端连接
通过bin目录下的zkCli.sh 命令连接即可
zkCli.sh
zkCli.sh默认连接的是当前节点的Zookeeper节点,如果我们要连接其他节点执行如下命令即可
zkCli.sh -timeout 5000 -server bobo02:2181
2_Zookeeper的数据结构
- 层次化的目录结构,命名符合常规文件系统规范
- 每个节点在 Z o o k e e p e r Zookeeper Zookeeper中叫做Znode,并且有一个唯一的路径标识
- 节点Znode可以包含数据和子节点(但是EPHEMERAL类型的节点不能有子节点)
- 客户端应用可以在节点上设置监听器
3_节点类型
1、znode有两种类型:
节点类型 | 说明 |
---|---|
持久节点(Persistent) | 即使客户端断开连接,节点依然存在(断开连接不删除)。 |
临时节点(Ephemeral) | 客户端会话结束后,节点会被自动删除(断开连接自己删除)。 |
顺序节点(Sequential) | Z o o k e e p e r Zookeeper Zookeeper 会为该节点分配一个顺序号,节点名会以顺序号形式命名。 |
容器节点(Container) | 是一种特殊的持久性节点,用于管理一组相关的子节点。 当容器的最后一个子节点被删除时,该容器将被删除。 |
知道前两种类型即可,第三种和第四种节点类型是我的一个补充。
2、znode有四种形式的目录节点(默认是persistent)如下
序号 | 节点类型 | 描述 |
---|---|---|
1 | PERSISTENT | 持久节点 |
2 | PERSISTENT_SEQUENTIAL | 持久有序节点 |
3 | EPHEMERAL | 短暂节点 |
4 | EPHEMERAL_SEQUENTIAL | 短暂有序节点 |
创建 Znode 时设置顺序标识,znode 名称后会附加一个值,顺序号是一个单调递增的计数器,有父节点维护在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序。
如果有多个Session创建同一个创建临时节点时让节点有序,则不会进行覆盖创建【Node already exists】,而是后面跟随一个递增的分布式序号(规避覆盖,分布式情况下统一命名)。
4_节点属性
一个 znode 节点不仅可以存储数据,还有一些其他特别的属性。
节点属性 | 注解 |
---|---|
cZxid | 该数据节点被创建时的事务Id |
ctime | 该数据节点创建时间 |
mZxid | 该数据节点被修改时最新的事物Id |
mtime | 该数据节点最后修改时间 |
pZxid | 当前节点的父级节点事务Id |
cversion | 子节点版本号(子节点修改次数,每修改一次值+1递增) |
dataVersion | 当前节点版本号(每修改一次值+1递增) |
aclVersion | 当前节点acl版本号(节点被修改acl权限,每修改一次值+1递增) |
ephemeralOwner | 临时节点标识,当前节点如果是临时节点, 则存储的创建者的会话id(sessionId),如果不是,那么值=0 |
dataLength | 当前节点所存储的数据长度 |
numChildren | 当前节点下子节点的个数 |
data | 数据(通常小于 1 MB),二进制安全 |
Zxid保证事务的顺序一致性
Z o o K e e p e r ZooKeeper ZooKeeper在选举时通过比较各结点的zxid和机器ID选出新的主结点。
Zxid由Leader节点生成,有新写入事件时,Leader生成新zxid并随提案一起广播,每个结点本地都保存了当前最近一次事务的 zxid,zxid 是递增的,所以谁的 zxid 越大,就表示谁的数据是最新的。
ZXID的生成规则如下:
ZXID 由两部分组成:
- 任期(Epoch):完成本次选举后,直到下次选举前,由同一Leader负责协调写入;
- 事务计数器:单调递增,每生效一次写入,计数器加一。
ZXID的高 32 位是 Epoch 用来标识朝代变化,比如每次选举 Epoch 都会加改变。
可以理解为当前集群所处的年代或者周期,每个 Leader 就像皇帝,都有自己的年号,所以每次改朝换代,Leader 变更之后,都会在前一个年代的基础上加 1。
这样就算旧的 Leader 崩溃恢复之后,也没有人听它的了。
ZXID的低 32 位是计数器,所以同一任期内,ZXID是连续的,每个结点又都保存着自身最新生效的ZXID,通过对比新提案的ZXID与自身最新ZXID是否相差“1”,来保证事务严格按照顺序生效的。
5_常用命令
推荐使用 help 查看命令使用,因为不同版本会有明显差异。
命令 | 描述 | 语法 | 示例 |
---|---|---|---|
help | 查看 Z o o k e e p e r Zookeeper Zookeeper 命令 | help |
help |
create | 创建一个新节点。-s 创建顺序节点,-e 创建临时节点,-c 创建容器节点,-t 设置 TTL。 |
create [-s] [-e] [-c] [-t ttl] path [data] [acl] |
create -e /tmpNode "data" world:anyone:crwda |
delete | 删除指定路径节点, (不能有子节点) -v 指定版本号,用于条件删除。 |
delete [-v version] path |
delete -v 1 /myNode |
deleteall | 递归删除指定节点及其所有子节点。 | deleteall path |
deleteall /myNode |
get | 获取指定路径的节点数据。-s 显示节点状态信息,-w 添加监听器。 |
get [-s] [-w] path |
get -s /myNode |
set | 更新指定节点的数据。-s 显示节点状态信息,-v 指定版本号。 |
set [-s] [-v version] path data |
set -s -v 1 /myNode "newData" |
ls | 列出指定路径节点的子节点。-s 显示节点状态信息,-w 添加监听器,-R 递归列出所有子节点。 |
ls [-s] [-w] [-R] path |
ls -s /myNode |
stat | 获取指定路径节点的统计信息。 (包括版本、修改时间等) -w 添加监听器。 |
stat [-w] path |
stat -w /myNode |
addWatch | 添加永久性的监听器 | addWatch [-m mode] path |
addWatch /myNode |
[-m mode] | 可选模式:[PERSISTENT, PERSISTENT_RECURSIVE] 之一,PERSISTENT 不监听子节点,RECURSIVE 递归监听子节点,默认使用递归策略。 |
addWatch -m PERSISTENT /myNode |
|
removewatches | 移除指定路径的监听器。-c 移除子节点监听器,-d 移除数据监听器,-a 移除所有监听器,-l 显示详细信息。 |
removewatches path [-c /-d /-a] [-l] |
removewatches /myNode -a -l |
printwatches | 设置是否打印监听器触发的事件,on 开启,off 关闭。 |
printwatches on / off |
printwatches on |
sync | 确保指定路径的节点数据与所有 Zookeeper 服务器同步。 | sync path |
sync /myNode |
connect | 连接到指定的 Zookeeper 服务器。 | connect host:port |
connect localhost:2181 |
close | 关闭当前会话, 但不退出 zkCli 工具。 |
close |
close |
quit | 退出 zkCli 工具。 |
quit |
quit |
version | 查看当前 Zookeeper 版本 |
version |
version |
addauth | 添加认证信息,scheme 是认证方案(如 digest ),auth 是认证信息。 |
addauth scheme auth |
addauth digest user:password |
whoami | 查看当前使用者信息 | whoami |
whoami |
setAcl | 设置指定节点的ACL (访问控制列表)。 -s 显示统计信息,-v 指定版本号,-R 递归设置所有子节点的 ACL。 |
setAcl [-s] [-v version] [-R] path acl |
setAcl -R /myNode world:anyone:crwda |
getAcl | 获取指定路径节点的 ACL 信息,-s 显示统计信息。 |
getAcl [-s] path |
getAcl -s /myNode |
config | 获取/设置 Zookeeper 配置信息。-c 只输出版本和连接信息,-w 用于添加监听器,-s 用于显示详细信息。 |
config [-c] [-w] [-s] |
config -s |
reconfig | 动态修改 Zookeeper 集群配置。-s 显示详细信息,-v 指定版本号。 |
reconfig [-s] [-v version] [options] |
reconfig -s |
[options] | 可选操作,[-members] ,[-add],[-remove],[-file path]
|
对节点动态变更配置的操作 | |
getAllChildrenNumber | 获取指定路径节点的所有子节点数量。 | getAllChildrenNumber path |
getAllChildrenNumber /myNode |
getEphemerals | 获取指定路径下的所有临时节点。 | getEphemerals path |
getEphemerals /myNode |
history | 显示命令历史记录。 | history |
history |
redo | 重新执行之前的命令,cmdno 是命令编号。与 history 配合使用 |
redo cmdno |
redo 1 |
注意事项
[ version ]
、[watch]
是老版本的可选参数,目前使用[-v]
,[-w]
代替,ls2
也被废弃,变为ls -s
。
以前的版本还有rmr
命令,现在也被废弃了,仅支持deleteall
。
addWatch
是 3.6.x 以后支持的永久性的递归监视,这些监视在触发时不会删除,并且会以递归方式触发注册Znode以及所有子Znode的更改。
Z
o
o
k
e
e
p
e
r
Zookeeper
Zookeeper 的 ACL 包含读(r
)、写(w
)、创建(c
)、删除(d
)、管理员(a
) 权限的设置。例如,world:anyone:cdrwa
表示所有用户均拥有创建、删除、读取和写入的权限。
reconfig
解决困扰已久的zk扩容,需要每台服务器都重新配置zoo.cfg
文件和重启zk的问题,这个功能需要在配置文件中提前开启。
6_Session
Client和 Z o o k e e p e r Zookeeper Zookeeper 集群建立连接,整个session状态变化如图所示:
如果 Client 因为 Timeout 和 Z o o k e e p e r Zookeeper Zookeeper Server 失去连接,client处在 CONNECTING 状态,会自动尝试再去连接Server,如果在 Session 有效期内再次成功连接到某个Server,则回到 CONNECTED 状态。
如果因为网络状态不好,Client和Server失去联系,client会停留在当前状态,会尝试主动再次连接 Z o o k e e p e r Zookeeper Zookeeper Server。
Client不能宣称自己的Session Expired,Session Expired是由 Z o o k e e p e r Zookeeper Zookeeper Server来决定的,Client可以选择自己主动关闭Session。
连接客户端的时候,会消耗一个事务id(简称Session也要消耗事务id即Zxid),断开连接也要统一所有节点所以还会消耗一个事务id。
Session会统一视图,所有节点一致,所以假设当前链接的节点当掉了,连到其他 follow 临时节点也不会消失。
7_Watcher事件监听
监听某个节点的数据内容变化,通过 get
命令 带 -w
参数即可,get path watch
实现监控的。
注意监听一次节点只会触发一次(3.6.x支持永久递归监视),如果要实现多次监听,那么可以在触发事件的处理函数中再次追加对节点的监听操作。
子节点的改变:
监听节点下面的子节点的改变。
[zk: localhost:2181(CONNECTED) 14] ls -w /app1
[]
Watcher监听机制的工作原理
Z o o k e e p e r Zookeeper Zookeeper 允许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher通知状态和事件类型做出业务上的改变。
可以把Watcher理解成客户端注册在某个Znode上的触发器,当这个Znode节点发生变化时(增删改查),就会触发Znode对应的注册事件,注册的客户端就会收到异步通知,然后做出业务的改变。
- Z o o K e e p e r ZooKeeper ZooKeeper的 Watcher 机制主要包括客户端线程、客户端 WatcherManager、 Z o o k e e p e r Zookeeper Zookeeper服务器三部分。
- 客户端向 Z o o K e e p e r ZooKeeper ZooKeeper服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的WatchManager中。
- 当 z o o k e e p e r zookeeper zookeeper服务器触发 watcher 事件后,会向客户端发送通知, 客户端线程从 WatcherManager 中取出对应的 Watcher 对象来执行回调逻辑。
Watcher 特性总结:
特性 | 说明 |
---|---|
一次性 | 一个Watch事件是一个一次性的触发器。 一次性触发,客户端只会收到一次这样的信息。 |
异步 |
Z
o
o
k
e
e
p
e
r
Zookeeper
Zookeeper服务器发送watcher的通知事件到客户端是异步的, 不能期望能够监控到节点每次的变化, Z o o k e e p e r Zookeeper Zookeeper只能保证最终的一致性,而无法保证强一致性。 |
轻量级 |
Watcher 通知非常简单, 它只是通知发生了事件,而不会传递事件对象内容。 |
客户端串行 | 执行客户端 Watcher 回调的过程是一个串行同步的过程。 |
注册 | 注册 watcher用 getData 、exists 、getChildren 方法 |
触发 | 触发 watcher用 create 、delete 、setData 方法 |