​ ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby一个开源的实现。它提供了简单原始的功能,分布式应用可以基于它实现更高级的服务,比如分布式同步, 配置管理, 集群管理, 命名管理,队列管理。它被设计为易于编程,使用文件系统目录树作为数据模型

特点

1、 最终一致性: client 不论连接到哪个 Server,展示给它都是同一个视图,这是 ZooKeeper最重要的性能。

2、 可靠性:具有简单、健壮、良好的性能,如果消息 m 被到一台服务器接受,那么它将被所有的服务器接受。

3、 实时性: ZooKeeper 保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。

但由于网络延时等原因, ZooKeeper 不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在

读数据之前调用 sync()接口

4、 等待无关(wait-free):慢的或者失效的 client 不得干预快速的 client 的请求,使得每个client 都能有效的等待

5、 原子性:更新只能成功或者失败,没有中间状态
6、 顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息 a 在消息 b前发布,则在所有Server 上消息 a 都将在消息 b 前被发布;偏序是指如果一个消息 b 在消息 a 后被同一个发送者发布, a 必将排在b 前面

zookeeper = 文件系统+事件监听

文件系统

ZooKeeper 的命名空间就是 ZooKeeper 应用的文件系统,它和 linux 的文件系统很像,也是树状,这样就可以确

定每个路径都是唯一的,对于命名空间的操作必须都是绝对路径操作。与linux 文件系统不同的是,linux 文件系

统有目录和文件的区别,而 ZooKeeper 统一叫做 znode,一个 znode 节点可以包含子 znode,同时也可以包含

数据所以总结说来, znode 即是文件夹又是文件的概念,所以在 ZooKeeper 这里面就不叫文件文件也不叫文件夹,叫 znode,每个 znode 有唯一的路径识,既能存储数据,也能创建子 znode。但是 znode 只适合存储非常小量的数据,不能超过 1M,最好小于 1K

事件监听

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、 节点删除、 子目录节点增加删除)时,ZooKeeper 会通知客户端。 监听机制保证 ZooKeeper 保存的任何的数据的任何改变都能快速的响应到监听了该节点的应用程序

ZooKeeper 的 Watcher 机制主要包括客户端线程、 客户端 WatcherManager、 Zookeeper 服务器三部分。客户端在向 ZooKeeper 服务器注册的同时,会将 Watcher 对象存储在客户端的WatcherManager 当中。当ZooKeeper 服务器触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatcherManager 中取出对应的Watcher 对象来执行回调逻辑

常用命令解析

help

查看客户端帮助命令

[zk: localhost:2181(CONNECTED) 8] help
ZooKeeper -server host:port cmd args
        stat path [watch]
        set path data [version]
        ls path [watch]
        delquota [-n|-b] path
        ls2 path [watch]
        setAcl path acl
        setquota -n|-b val path
        history
        redo cmdno
        printwatches on|off
        delete path [version]
        sync path
        listquota path
        rmr path
        get path [watch]
        create [-s] [-e] path data acl
        addauth scheme auth
        quit
        getAcl path
        close
        connect host:port
创建

create [-s] [-e] path data acl

-s和-e分别指定节点特性:顺序或临时节点,acl是权限控制

[zk: localhost:2181(CONNECTED) 11] create /name my
Created /name
读取

ls path [watch]

[zk: localhost:2181(CONNECTED) 38] ls /
[zookeeper, name, dubbo]

get path [watch]

[zk: localhost:2181(CONNECTED) 39] get /name
my
cZxid = 0xe17
ctime = Thu Oct 31 15:07:37 CST 2019
mZxid = 0xe17
mtime = Thu Oct 31 15:07:37 CST 2019
pZxid = 0xe17
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 2
numChildren = 0

详细信息

  • my:节点的值,如果值则空一行
  • cZxid :创建节点的事务id
  • ctime : 节点的创建时间
  • mZxid :修改节点的事务id
  • mtime :修改节点的时间
  • pZxid :子节点的id
  • cversion : 子节点的版本
  • dataVersion : 当前节点数据的版本
  • aclVersion :权限的版本
  • ephemeralOwner :判断是否是临时节点
  • dataLength : 数据的长度
  • numChildren :子节点的数量
更新

set path data [version]

[zk: localhost:2181(CONNECTED) 45] set /name mingyu
cZxid = 0xe17
ctime = Thu Oct 31 15:07:37 CST 2019
mZxid = 0xe27
mtime = Thu Oct 31 15:26:13 CST 2019
pZxid = 0xe17
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
# 版本号更新,因为/name节点的版本号是2了所以执行版本号为1时,更新失败
[zk: localhost:2181(CONNECTED) 46] set /name my 1
version No is not valid : /name
# 更新成功
[zk: localhost:2181(CONNECTED) 47] set /name my 2
cZxid = 0xe17
ctime = Thu Oct 31 15:07:37 CST 2019
...
删除

delete path [version]

[zk: localhost:2181(CONNECTED) 55] delete /name
# 删除不是当前版本号的节点
[zk: localhost:2181(CONNECTED) 60] delete /name 0
version No is not valid : /name

除了版本号不一致不能进行删除外,如果要删除的节点有子节点也是不能进行删除的

[zk: localhost:2181(CONNECTED) 75] delete /name
Node not empty: /name

watch通知

通过help命令查看带有watch选项的命令,可以对当前操作节点增加监听操作的

带有watch选项的命令:stat,get,ls,ls2

stat 设置监听
[zk: localhost:2181(CONNECTED) 82] stat /test watch
Node does not exist: /test
[zk: localhost:2181(CONNECTED) 83] create /test test
Created /test
WATCHER::
# NodeCreated表示创建节点,路径是:/test
WatchedEvent state:SyncConnected type:NodeCreated path:/test
get 设置监听
[zk: localhost:2181(CONNECTED) 84] get /test watch
test
cZxid = 0xe39
ctime = Thu Oct 31 16:12:12 CST 2019
mZxid = 0xe39
mtime = Thu Oct 31 16:12:12 CST 2019
pZxid = 0xe39
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 85] set /test 1

WATCHER::cZxid = 0xe39
# NodeDataChanged 节点数据改变,路径是:/test
WatchedEvent state:SyncConnected type:NodeDataChanged path:/testctime = Thu Oct
31 16:12:12 CST 2019

mZxid = 0xe3a
mtime = Thu Oct 31 16:14:25 CST 2019
pZxid = 0xe39
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
ls 设置监听
[zk: localhost:2181(CONNECTED) 86] ls /test watch
[]
[zk: localhost:2181(CONNECTED) 87] create /test/date date

WATCHER::Created /test/date
# NodeChildrenChanged 子节点发生改变,路径是:/test
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/test
ls2

ls命令和stat命令的整合

[zk: localhost:2181(CONNECTED) 88] ls2 /test watch
[date]
cZxid = 0xe39
ctime = Thu Oct 31 16:12:12 CST 2019
mZxid = 0xe3a
mtime = Thu Oct 31 16:14:25 CST 2019
pZxid = 0xe3b
cversion = 1
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 1
numChildren = 1

利用ls2命令给/test节点加上监听

# 对子节点的数据进行修改不会触犯watch监听
[zk: localhost:2181(CONNECTED) 89] set /test/date 1
cZxid = 0xe3b
ctime = Thu Oct 31 16:18:09 CST 2019
mZxid = 0xe3c
mtime = Thu Oct 31 16:21:46 CST 2019
pZxid = 0xe3b
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
# 只有创建子节点和删除子节点时会触发watch监听
[zk: localhost:2181(CONNECTED) 94] delete /test/date

WATCHER::
# NodeDeleted 节点删除,路径:/test/date
WatchedEvent state:SyncConnected type:NodeDeleted path:/test/date

acl 权限

zookeeper使用ACL权限控制机制来保障数据安全

zookeeper中的节点有5种操作权限:CREATEREADWRITEDELETEADMIN 对应的就是增、查、改、删、管理权限,这5种权限简写为crwda

注:这5种权限中,delete是指对子节点的删除权限,其它4种权限指对自身节点的操作权限

权限模式:Scheme

ip

​ ip模式通过ip地址粒度来进行权限控制,例如配置了:ip:192.168.1.100即表示权限控制都是针对这个ip地址的,同时也支持按网段分配,比如:192.168.1.*

Digest

​ Digest是最常用的权限控制模式,类似于username:password形成的权限标识来进行权限配置,zookeeper会对形成的权限标识先后进行两次编码处理,分别是SHA-1加密算法,BASE64编码。

World

​ World是一种最开放的权限控制模式,这种权限控制方式几乎没有任何作用,数据节点的访问权限对所有用户开放,即所有用户都可以在不进行任何权限校验的情况下操作ZooKeeper上的数据。World模式也可以看作是一种特殊的Digest模式,它只有一个权限标识,即world:anyone 默认权限

Super

​ Super模式是一种特殊的Digest模式,在Super模式下,超级用户可以对任意ZooKeeper上的数据节点进行任何操作

通过help名称查看带有acl关键字的名,包括:getAcl,setAcl,create

使用:[scheme:id:permissions]来表示acl权限

world模式

格式:world:anyone:permissions

查询权限

getAcl path

[zk: localhost:2181(CONNECTED) 96]  getAcl /name
'world,'anyone
: cdrwa

world:认证方式,anyone:任何人,cdrwa:权限

所以我们可以对/name节点进行任何操作

设置权限

setAcl path acl

[zk: localhost:2181(CONNECTED) 123] setAcl /acl world:anyone:cw
cZxid = 0xe4e
ctime = Thu Oct 31 17:01:41 CST 2019
mZxid = 0xe4e
mtime = Thu Oct 31 17:01:41 CST 2019
pZxid = 0xe4e
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 2
numChildren = 0

对/name节点增加create和write权限,我们测试一下

# 因为没有读的权限,所以get提示没权限
[zk: localhost:2181(CONNECTED) 124] get /acl
Authentication is not valid : /acl
# 改节点数据的时候操作正常
[zk: localhost:2181(CONNECTED) 125] set /acl my
cZxid = 0xe4e
ctime = Thu Oct 31 17:01:41 CST 2019
mZxid = 0xe52
mtime = Thu Oct 31 17:03:45 CST 2019
pZxid = 0xe4e
cversion = 0
dataVersion = 1
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 2
numChildren = 0

Digest模式

格式: scheme:username:password:permissions

Digest模式中 scheme 分为两种:digest和auto

scheme:digest

# 设置权限
[zk: localhost:2181(CONNECTED) 135] setAcl /acl digest:name:my:cr
cZxid = 0xe56
ctime = Thu Oct 31 17:29:12 CST 2019
mZxid = 0xe56
mtime = Thu Oct 31 17:29:12 CST 2019
pZxid = 0xe56
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
# 获取权限,密码没加密
[zk: localhost:2181(CONNECTED) 136] getAcl /acl
'digest,'name:my
: cr

scheme:auto

使用 addauth scheme auth 命令增加

# 使用auto 设置权限
[zk: localhost:2181(CONNECTED) 153] addauth digest a:a
# 获取权限,password加密了
[zk: localhost:2181(CONNECTED) 4] getAcl /cmy
'digest,'a:mDmPUap4qvYwm+PZOtJ/scGyHLY=
: crw
ip

格式:ip:Ip-address:permissions

# 设置权限
[zk: localhost:2181(CONNECTED) 9] setAcl /ip ip:192.168.1.1:cr
cZxid = 0xe6a
ctime = Thu Oct 31 17:50:29 CST 2019
mZxid = 0xe6a
mtime = Thu Oct 31 17:50:29 CST 2019
pZxid = 0xe6a
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
# 查看权限
[zk: localhost:2181(CONNECTED) 10] getAcl /ip
'ip,'192.168.1.1
: cr