Zookeeper入门
Zookeeper
一、概念
是一个开放源代码的分布式协调服务,由知名互联网公司雅虎创建。设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构建成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。
zookeeper是一个典型的分布式一致性解决方案,分布式应用系统可以基于它实现诸如数据发布/订阅,负载均衡,命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。Zookeeper可以保证如下分布式一致性特性。
二、zookeeper特性
- 一致性:数据一致性,数据按照顺序分批入库
- 原子性:事务要么成功要么失败,不会局部化
- 单一视图:客户端连接集群中的任一zk节点,数据都是一致的
- 可靠性:每次对zk的操作状态都会保存在服务端
- 实时性:客户端最终可以读取到zk服务端的最新数据(一定时间段内)
三、Zookeeper主要目录结构
- bin:主要的一些运行命令
- conf:存放配置文件,其中需要修改zoo.cfg(zoo_sample.cfg)
- contrib:附加的一些功能
- dist-manven:mvn编译后的目录(包含一些jar包和pomw文件)
- docs:文档
- lib:平时开发所需要依赖的jar包(在后续开发java客户端的时候用到)
- recipes:经典案例demo代码(包括lock锁和队列等)
- src:源码
四、zoo.cfg配置
从zoo_sample.cfg拷贝一份新的zoo.cfg放在同一个目录下。
- tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳,ZooKeeper使用的基本时间单位(以毫秒为单位)。
- dataDir:Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
- dataLogDir:Zookeeper 保存日志文件的目录
- clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
windows环境下:
dataDir=D:\common\zookeeper-3.4.14\zookeeper-3.4.14\dataDir
dataLogDir=D:\common\zookeeper-3.4.14\zookeeper-3.4.14\dataLog
linux环境下:
dataDir=/usr/local/zookeeper/zookeeper-3.4.14/dataDir
dataLogDir=/usr/local/zookeeper/zookeeper-3.4.14/dataLogDir
五、 Zookeeper的基本数据模型介绍
- 是一个树形结构
- 每一个节点都成为znode,它可以有子节点,也可以有数据
- 每个节点还可以分为临时节点(seesion失效数据丢失)和永久节点(session失效数据不丢失),临时节点在客户端断开后消失
- 每个节点都有各自的版本号,可以通过命令行来显示节点信息
- 每当节点的数据发生变化,那么该节点的版本号会累加(乐观锁)
- 删除/修改过时节点,版本号不匹配会报错(当前节点已被别人修改过,不再匹配,也是使用乐观锁的思想)
- 每个zk节点存储的数据不宜过大,几k即可
- 节点可以设置权限acl,可以通过权限来限制用户的访问
六、Zookeeper作用
-
master节点选举,主节点挂了以后,从节点就会接手工作,并且保证这个节点是唯一的,这就是所谓的首脑模式,从而保证集群高可用
-
统一配置文件管理:即只需要修改其中一台服务器的文件,就可以把相同配置的文件同步更新到其它所有服务器
-
发布与订阅,类似消息队列MQ,dubbo发布者把数据存放到znode上,订阅者会读取这个数据
-
提供分布式锁
-
集群管理(主从数据同步),集群中保证数据强一致性
七、常用命令行操作
- 在bin目录下通过 ./zkServer.sh start 启动zookeeper
- 查看 zookeeper状态 ./zkServer.sh status
- 通过 ./zkCli.sh 连接zk的客户端进入命令行后台
- ls 命令
ls path [watch ] 指可以查看某一个节点下有哪些子节点列表,watch是一个监视器
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /zookeeper
[quota]
[zk: localhost:2181(CONNECTED) 2] ls /zookeeper/quota
[]
[zk: localhost:2181(CONNECTED) 3]
/ 就是根节点,zookeeper就是父节点, quota就是子节点
- ls2 命令
ls2 path [watch ] 指查看当前节点的子节点和状态信息
[zk: localhost:2181(CONNECTED) 3] ls2 /
[zookeeper] //当前节点的子节点
cZxid = 0x0 //Zookeeper为节点分配的Id
ctime = Wed Dec 31 19:00:00 EST 1969 //节点创建时间
mZxid = 0x0 //修改后的id
mtime = Wed Dec 31 19:00:00 EST 1969 //修改时间
pZxid = 0x0 //子节点id
cversion = -1 //子节点的version
dataVersion = 0 //当前节点数据版本
aclVersion = 0 //权限版本
ephemeralOwner = 0x0
dataLength = 0 // 数据长度
numChildren = 1 //子节点个数
- stat 命令
stat path
stat只显示节点的状态信息,不显示当前节点的子节点
可以看出,ls2 = ls + stat
[zk: localhost:2181(CONNECTED) 4] stat /
cZxid = 0x0
ctime = Wed Dec 31 19:00:00 EST 1969
mZxid = 0x0
mtime = Wed Dec 31 19:00:00 EST 1969
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
- get 命令
get path
将当前节点存储的数据提取出来(数据 不存在则为空)
[zk: localhost:2181(CONNECTED) 14] get /testzoo
nihaoa
cZxid = 0x2
ctime = Mon Apr 22 05:29:06 EDT 2019
mZxid = 0x2
mtime = Mon Apr 22 05:29:06 EDT 2019
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
- create 命令
create [-s] [-e] path data acl
[zk: localhost:2181(CONNECTED) 10] create /testzoo nihaoa
Created /testzoo
当我们创建的时候在指令上加上 -e 我们会创建一个临时的节点
[zk: localhost:2181(CONNECTED) 17] create -e /testzoo/test nihaoa2
Created /testzoo/test
[zk: localhost:2181(CONNECTED) 18] get /testzoo
nihaoa
cZxid = 0x2
ctime = Mon Apr 22 05:29:06 EDT 2019
mZxid = 0x2
mtime = Mon Apr 22 05:29:06 EDT 2019
pZxid = 0x4
cversion = 1 //版本号+1了
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 1
会发现此时 节点 /testzoo 的 cversion=1 (版本号+1了)
[zk: localhost:2181(CONNECTED) 20] get /testzoo/test
nihaoa2
cZxid = 0x4
ctime = Mon Apr 22 05:36:20 EDT 2019
mZxid = 0x4
mtime = Mon Apr 22 05:36:20 EDT 2019
pZxid = 0x4
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x100000a70750000 //不再是OXO了,变化了
dataLength = 7
numChildren = 0
可以看到此时ephemeralOwner = 0x100000a70750000,不再是OXO了,说明这个节点是一个临时节点。
当我们创建的时候在指令上加上 -s 我们会创建一个顺序节点
[zk: localhost:2181(CONNECTED) 8] create -s /testzoo/niuniuniu seq
Created /testzoo/niuniuniu0000000005
[zk: localhost:2181(CONNECTED) 9] create -s /testzoo/niuniuniu seq
Created /testzoo/niuniuniu0000000006
[zk: localhost:2181(CONNECTED) 10] create -s /testzoo/niuniuniu seq
Created /testzoo/niuniuniu0000000007
[zk: localhost:2181(CONNECTED) 11] create -s /testzoo/niuniuniu seq
Created /testzoo/niuniuniu0000000008
[zk: localhost:2181(CONNECTED) 12] create -s /testzoo/niuniuniu seq
Created /testzoo/niuniuniu0000000009
- set 命令
set path data [version] 通过版本号修改某一节点的值
[zk: localhost:2181(CONNECTED) 26] set /testzoo '测试一下' 2
cZxid = 0x2
ctime = Mon Apr 22 05:29:06 EDT 2019
mZxid = 0x1c
mtime = Mon Apr 22 05:58:59 EDT 2019
pZxid = 0x15
cversion = 11
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 9
[zk: localhost:2181(CONNECTED) 27] get /testzoo
测试一下
cZxid = 0x2
ctime = Mon Apr 22 05:29:06 EDT 2019
mZxid = 0x1c
mtime = Mon Apr 22 05:58:59 EDT 2019
pZxid = 0x15
cversion = 11
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 9
- delete 命令
删除某个节点 如果不加版本号则会删除这个节点
[zk: localhost:2181(CONNECTED) 28] ls /testzoo
[zoooo, test, niuniuniu0000000009, niuniuniu0000000008, niuniuniu0000000007, momo, niuniuniu0000000006, niuniuniu0000000005, demo]
[zk: localhost:2181(CONNECTED) 29] delete /testzoo/niuniuniu0000000005
[zk: localhost:2181(CONNECTED) 30] delete /testzoo/niuniuniu0000000006
[zk: localhost:2181(CONNECTED) 31] delete /testzoo/niuniuniu0000000007
[zk: localhost:2181(CONNECTED) 32] delete /testzoo/niuniuniu0000000008
[zk: localhost:2181(CONNECTED) 33] ls /testzoo
[zoooo, test, niuniuniu0000000009, momo, demo]
[zk: localhost:2181(CONNECTED) 34]
如果加上版本号只会去删除掉对应的版本号的节点数据,如果版本号不对应则报错版本号无效
[zk: localhost:2181(CONNECTED) 40] delete /testzoo/niuniuniu0000000009 0
version No is not valid : /testzoo/niuniuniu0000000009
八、zk特性-watcher机制
- 针对每一个节点的操作都会有一个监督者 -> watcher
- 当监控的某个节点(znode)发生增删改变化时都会触发一个watcher事件
- zk中的watch是一次性的,触发后立即销毁
- 针对不同类型的操作,触发的watch事件也是不同:
1.(子/父)节点创建事件
2.(子/父)节点删除事件
3.(子/父)节点修改事件
8.1 Watcher命令行学习
- 通过get path [watch]设置watcher
[zk: localhost:2181(CONNECTED) 45] get /testzoo watch
测试一下
cZxid = 0x2
ctime = Mon Apr 22 05:29:06 EDT 2019
mZxid = 0x1c
mtime = Mon Apr 22 05:58:59 EDT 2019
pZxid = 0x23
cversion = 16
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 4
给节点 /testzoo 设置一个监听器(监督者)
8.2 watcher事件类型
8.2.1 父节点watcher事件类型
- 创建父节点触发:NodeCreated事件
stat /demozookeeper watch :给节点 /demozookeeper 设置一个监听器(监督者),当创建 /demozookeeper时,触发了watcher事件,事件类型是type:NodeCreated,path:/demozookee为此次watcher监听的节点。
[zk: localhost:2181(CONNECTED) 50] stat /demozookeeper watch
Node does not exist: /demozookee
[zk: localhost:2181(CONNECTED) 52] create /demozookee '你好世界'
WATCHER::
WatchedEvent state:SyncConnected type:NodeCreated path:/demozookee
Created /demozookee
[zk: localhost:2181(CONNECTED) 53]
- 修改父节点数据触发:NodeDataChanged事件
给 /testzoo 设置一个监听器,当节点 /testzoo 修改时,触发了watcher事件,事件类型是type:NodeDataChanged,path:/testzoo为此次监听器watcher所监听的节点。
[zk: localhost:2181(CONNECTED) 45] get /testzoo watch
测试一下
cZxid = 0x2
ctime = Mon Apr 22 05:29:06 EDT 2019
mZxid = 0x1c
mtime = Mon Apr 22 05:58:59 EDT 2019
pZxid = 0x23
cversion = 16
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 4
[zk: localhost:2181(CONNECTED) 46] set /testzoo '你还好吗?'
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/testzoo
cZxid = 0x2
ctime = Mon Apr 22 05:29:06 EDT 2019
mZxid = 0x24
mtime = Mon Apr 22 06:52:23 EDT 2019
pZxid = 0x23
cversion = 16
dataVersion = 4
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 15
numChildren = 4
- 删除父节点触发:NodeDeleted
删除父节点 /demozookee 时触发 type:NodeDeleted 事件,path:/demozookee为此次监听器(watcher)所监听的节点。
[zk: localhost:2181(CONNECTED) 56] get /demozookee watch
啥啊?
cZxid = 0x27
ctime = Mon Apr 22 06:58:28 EDT 2019
mZxid = 0x28
mtime = Mon Apr 22 07:09:48 EDT 2019
pZxid = 0x27
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
[zk: localhost:2181(CONNECTED) 57] delete /demozookee
WATCHER::
WatchedEvent state:SyncConnected type:NodeDeleted path:/demozookee
8.2.2 watcher子节点事件类型
- ls为父节点设置watcher(使用get命令为父节点设置watcher不会触发子节点创建事件),创建子节点触发:NodeChildrenChanged
[zk: localhost:2181(CONNECTED) 73] ls /testzoo watch
[zoooo, test, momo, nodetest1, nodetest3, nodetest2, demo]
[zk: localhost:2181(CONNECTED) 74] create /testzoo/nodetest4 node4
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/testzoo
Created /testzoo/nodetest4
- ls为父节点设置watcher(使用get命令为父节点设置watcher不会触发子节点创建事件),删除子节点触发:NodeChildrenChanged
[zk: localhost:2181(CONNECTED) 2] ls /testzoo watch
[test, nodetest4, nodetest1, nodetest3, nodetest2, demo]
[zk: localhost:2181(CONNECTED) 3] delete /testzoo/test
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/testzoo
- ls为父节点设置watcher,修改子节点不触发事件(必须要把子节点当做父节点来设置watcher方可触发事件)
[zk: localhost:2181(CONNECTED) 4] ls /testzoo watch
[nodetest4, nodetest1, nodetest3, nodetest2, demo]
[zk: localhost:2181(CONNECTED) 5] set /testzoo/nodetest2 jjjjjjj
cZxid = 0x2a
ctime = Mon Apr 22 21:31:37 EDT 2019
mZxid = 0x32
mtime = Mon Apr 22 21:52:17 EDT 2019
pZxid = 0x2a
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0
8.3 watcher使用场景
- 进行统一资源配置
即更新主机上新的配置信息时,根据watcher事件,同步更新集群中所有客户端的配置信息。
- 降级开关
比如秒杀等场景,当mq集群挂了的时候,此时可以用zookeeper的watcher做降级开关,生产者不再将消息写入mq集群,而去用降级服务(比如使用redis做的发布订阅功能)
九、ACL权限控制
- 针对节点可以设置相关的读写等权限,目的是为了保障数据的安全性
- 权限permissions可以指定不同的权限范围以及角色
- getAcl:获取某个节点的acl权限信息
- setAcl:设置某个节点的acl权限信息
- addauth:新注册用户(密码是明文的,但是在zk系统里密码是以加密的形式存在的)或登录用户
9.1 ACL的构成
- zk的acl通过[scheme?permission]来构成权限列表
- scheme:代表采用的某种权限机制 (五种权限机制 一般常用的为四种)
- id:代表允许访问的用户
- permissions:权限组合的字符串
9.1.1 scheme
- wolrd:world下只有一个id,即只有一个用户,也就是anyone,那么组合的写法就是 world:anyone:[permissions](即任何人都有权限访问这个节点)
- auth:代表认证登录,即用户登录之后才有的权限,写法是auth:user:password:[peemissions]
- digest:需要对密码加密才能访问,组合形式为digest:username:BASE64(SHA1(password)):[permissions]
其实,auth和digest的区别就是,前者明文,后者密文,而setAcl /path auth:lee:lee:cdrwa与setAcl /path auth:lee:BASE64(SHA1(lee)):cdrwa是等价的,通过addauth digest lee:lee 后都能操作指定节点的权限
- ip:当设置为ip指定的ip地址,此时限制ip进行访问,比如ip:192.168.1.1:[permissions]
- super:表示超级管理员,拥有所有的权限
9.1.2 permissions
权限字符串缩写 crdwa
- c(CERATE):创建子节点
- r(READ):获取节点/子节点
- d(DELETE):删除子节点
- w(WRITE):设置子节点
- a(ADMIN):设置权限
9.1.3 ACL命令行的使用
9.1.3.1 world:anyone: cdrwa
(1)节点 /testzoo/demo 拥有的是默认权限(即所有增删改查权限)
[zk: localhost:2181(CONNECTED) 10] getAcl /testzoo/demo
'world,'anyone
: cdrwa
(2)权限不足,无法操作
创建 /testzoo/demo节点 的子节点 /testzoo/demo/momomo,并给 /testzoo/demo 节点重新授权 world:anyone:crwa
此时所有用户没有删除子节点的权限,当删除 /testzoo/demo 节点 的子节点 /testzoo/demo/momomo 时,会报异常 Authentication is not valid (身份验证无效)
[zk: localhost:2181(CONNECTED) 16] create /testzoo/demo/momomo '你好啊!'
Created /testzoo/demo/momomo
[zk: localhost:2181(CONNECTED) 18] getAcl /testzoo/demo
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 19] setAcl /testzoo/demo world:anyone:crwa
cZxid = 0x9
ctime = Mon Apr 22 05:49:36 EDT 2019
mZxid = 0x9
mtime = Mon Apr 22 05:49:36 EDT 2019
pZxid = 0x37
cversion = 3
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
[zk: localhost:2181(CONNECTED) 20] getAcl /testzoo/demo
'world,'anyone
: crwa
[zk: localhost:2181(CONNECTED) 21] delete /testzoo/demo/momomo
Authentication is not valid : /testzoo/demo/momomo
我们给 /testzoo/demo 节点 重新授权 world:anyone:a
这时所有用户对当前节点只有设置权限的权限,没有查询当前节点信息的权限,也没有更改数据的权限,更没有操作子节点的权限。
[zk: localhost:2181(CONNECTED) 23] setAcl /testzoo/demo world:anyone:a
cZxid = 0x9
ctime = Mon Apr 22 05:49:36 EDT 2019
mZxid = 0x9
mtime = Mon Apr 22 05:49:36 EDT 2019
pZxid = 0x37
cversion = 3
dataVersion = 0
aclVersion = 2
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
[zk: localhost:2181(CONNECTED) 24] getAcl /testzoo/demo
'world,'anyone
: a
[zk: localhost:2181(CONNECTED) 25] ls2 /testzoo/demo
Authentication is not valid : /testzoo/demo
9.1.3.2 auth:user:pwd:cdrwa、digest:user:BASE64(SHA1(pwd)):cdrwa、addauth digest user:pwd
(1)setAcl /testzoo/demo auth:lee:lee:cdrwa: 我们对 /testzoo/demo 节点重新设置权限 auth:lee:lee:cdrwa,被告知 Acl is not valid : /testzoo/demo ,是因为用户没有注册,此时需要先注册用户
(2)addauth digest lee:lee: 注册用户lee
(3)setAcl /testzoo/demo auth:lee:lee:cdrwa: 重新设置权限,此时设置成功
(4)getAcl /testzoo/demo: 查询权限,发现用户的密码被加密了
[zk: localhost:2181(CONNECTED) 29] setAcl /testzoo/demo auth:lee:lee:cdrwa
Acl is not valid : /testzoo/demo
[zk: localhost:2181(CONNECTED) 30] addauth digest lee:lee
[zk: localhost:2181(CONNECTED) 31] setAcl /testzoo/demo auth:lee:lee:cdrwa
cZxid = 0x9
ctime = Mon Apr 22 05:49:36 EDT 2019
mZxid = 0x9
mtime = Mon Apr 22 05:49:36 EDT 2019
pZxid = 0x37
cversion = 3
dataVersion = 0
aclVersion = 4
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
[zk: localhost:2181(CONNECTED) 32] getAcl /testzoo/demo
'digest,'lee:MzFvWNvXCPbX2fkwvXZavrxqQGo=
: cdrwa
(5)create /testzoo/demo2: 创建一个新的节点/testzoo/demo2
(6)setAcl /testzoo/demo2digest:lee:MzFvWNvXCPbX2fkwvXZavrxqQGo=:cdraw: 给 /testzoo/demo2 节点 设置权限 digest:lee:MzFvWNvXCPbX2fkwvXZavrxqQGo=:cdraw
(7)getAcl /testzoo/demo2: 查询 /testzoo/demo2 节点的权限。
[zk: localhost:2181(CONNECTED) 37] create /testzoo/demo2 '啊哈哈'
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/testzoo
Created /testzoo/demo2
[zk: localhost:2181(CONNECTED) 41] setAcl /testzoo/demo2 digest:lee:MzFvWNvXCPbX2fkwvXZavrxqQGo=:cdraw
cZxid = 0x41
ctime = Tue Apr 23 02:16:51 EDT 2019
mZxid = 0x41
mtime = Tue Apr 23 02:16:51 EDT 2019
pZxid = 0x41
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
[zk: localhost:2181(CONNECTED) 42] getAcl /testzoo/demo2
'digest,'lee:MzFvWNvXCPbX2fkwvXZavrxqQGo=
: cdrwa
[zk: localhost:2181(CONNECTED) 43]
digest与auth的区别一个密文,一个是明文,但是保存的时候都是密文的,他们是等价的。
9.1.3.3 ip:192.168.1.1:cdrwa
(1)create /testzoo/ip ipnnn:创建 /testzoo/ip 节点
(2)setAcl /testzoo/ip ip:192.168.1.1:cdrwa :给 /testzoo/ip 节点设置ip权限,只有ip:192.168.1.1的ip能够访问这个节点。
[zk: localhost:2181(CONNECTED) 43] create /testzoo/ip ipnnn
Created /testzoo/ip
[zk: localhost:2181(CONNECTED) 46] setAcl /testzoo/ip ip:192.168.1.1:cdrwa
cZxid = 0x43
ctime = Tue Apr 23 02:37:01 EDT 2019
mZxid = 0x43
mtime = Tue Apr 23 02:37:01 EDT 2019
pZxid = 0x43
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 20
numChildren = 0
[zk: localhost:2181(CONNECTED) 47] getAcl /testzoo/ip
Authentication is not valid : /testzoo/ip
[zk: localhost:2181(CONNECTED) 48] ls /testzoo/ip
Authentication is not valid : /testzoo/ip
[zk: localhost:2181(CONNECTED) 49]
9.1.3.4 超级用户设置
(1)修改zkServer.sh增加super管理员
加入 "-Dzookeeper.DigestAuthenticationProvider.superDigest=admin:x1nq8J5GOJVPY6zgzhtTtA9izLc="
(2)重启 zkServer.sh
./zkServer.sh restart
(3)重新进入zk命令行后台,查看 /testzoo/demo2 的信息,报异常(Authentication is not valid),当登录 admin 超级用户后,查看再无任何权限问题。
[zk: localhost:2181(CONNECTED) 1] ls /testzoo/demo2
Authentication is not valid : /testzoo/demo2
[zk: localhost:2181(CONNECTED) 2] addauth digest admin:admin
[zk: localhost:2181(CONNECTED) 3] ls /testzoo/demo2
[]
[zk: localhost:2181(CONNECTED) 4] ls2 /testzoo/demo2
[]
cZxid = 0x41
ctime = Tue Apr 23 02:16:51 EDT 2019
mZxid = 0x41
mtime = Tue Apr 23 02:16:51 EDT 2019
pZxid = 0x41
cversion = 0
dataVersion = 0
aclVersion = 2
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
9.2 zookeeper四字命令
(1)Zookeeper通过自身简写命令来和服务器进行交互
(2)需要使用到nc命令,安装:yum install nc
(3)使用方法:echo stat(ruok/dump等命令) | nc localhost 2181
stat命令
查看zk的状态信息,以及是否mode(集群还是单机)
Mode: standalone,代表是单机的
[root@localhost /]# echo stat | nc localhost 2181
Zookeeper version: 3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
Clients:
/0:0:0:0:0:0:0:1:56582[0](queued=0,recved=1,sent=0)
Latency min/avg/max: 0/0/5
Received: 133
Sent: 132
Connections: 1
Outstanding: 0
Zxid: 0x48
Mode: standalone //代表是单机
Node count: 15
ruok命令
查看当前zkServer是否启动,返回imok则说明启动的
[root@localhost /]# echo ruok | nc localhost 2181
imok[root@localhost /]#
dump命令
列出未经处理的会话和临时节点,可以看到当前未经处理的会话和临时节点都是0,因为没有连接客户端
[root@localhost /]# echo dump | nc localhost 2181
SessionTracker dump:
Session Sets (0): //会话 0
ephemeral nodes dump:
Sessions with Ephemerals (0): //节点 0
conf命令
查看服务器配置
[root@localhost /]# echo conf | nc localhost 2181
clientPort=2181
dataDir=/usr/local/zookeeper/zookeeper-3.4.14/dataDir/version-2
dataLogDir=/usr/local/zookeeper/zookeeper-3.4.14/dataLogDir/version-2
tickTime=2000
maxClientCnxns=60
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=0
cons命令
展示连接到服务器的客户端信息
[root@localhost /]# echo cons | nc localhost 2181
/0:0:0:0:0:0:0:1:56590[0](queued=0,recved=1,sent=0)
envi命令
查看zookeeper的环境变量
[root@localhost /]# echo envi | nc localhost 2181
Environment:
zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
host.name=localhost
java.version=1.8.0_211
java.vendor=Oracle Corporation
java.home=/usr/local/java/jdk1.8.0_211/jre
java.class.path=/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-server/target/classes:/usr/local/zookeeper/zookeeper-3.4.14/bin/../build/classes:/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-server/target/lib/*.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../build/lib/*.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/slf4j-log4j12-1.7.25.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/slf4j-api-1.7.25.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/netty-3.10.6.Final.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/log4j-1.2.17.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/jline-0.9.94.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/audience-annotations-0.5.0.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-3.4.14.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-server/src/main/resources/lib/*.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../conf:/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-server/target/classes:/usr/local/zookeeper/zookeeper-3.4.14/bin/../build/classes:/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-server/target/lib/*.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../build/lib/*.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/slf4j-log4j12-1.7.25.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/slf4j-api-1.7.25.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/netty-3.10.6.Final.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/log4j-1.2.17.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/jline-0.9.94.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../lib/audience-annotations-0.5.0.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-3.4.14.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../zookeeper-server/src/main/resources/lib/*.jar:/usr/local/zookeeper/zookeeper-3.4.14/bin/../conf:/usr/local/java/jdk1.8.0_211/lib/
java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
java.io.tmpdir=/tmp
java.compiler=<NA>
os.name=Linux
os.arch=amd64
os.version=3.10.0-693.el7.x86_64
user.name=root
user.home=/root
user.dir=/usr/local/zookeeper/zookeeper-3.4.14/bin
[root@localhost /]#
mntr命令
查看zk的健康信息
[root@localhost /]# echo mntr | nc localhost 2181
zk_version 3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
zk_avg_latency 0
zk_max_latency 5
zk_min_latency 0
zk_packets_received 139
zk_packets_sent 138
zk_num_alive_connections 1
zk_outstanding_requests 0
zk_server_state standalone
zk_znode_count 15
zk_watch_count 0
zk_ephemerals_count 0
zk_approximate_data_size 291
zk_open_file_descriptor_count 27
zk_max_file_descriptor_count 4096
zk_fsync_threshold_exceed_count 0
[root@localhost /]#
wchs命令
查看watch的信息
[root@localhost /]# echo wchs | nc localhost 2181
0 connections watching 0 paths
Total watches:0
十、zookeeper 集群搭建
- zookeeper集群、主从节点、心跳机制(选举模式)
- 需要注意:环境变量的配置,ip配置不同,端口号一般保持相同
- 集群测试,选举测试
十一、常用的zk java客户端
- zk原生api
- zkclient
- Apache curator(强烈推荐)
11.1 zk原生api的不足之处
- 超时重连,不支持自动,需要手动操作
- watch注册一次后失效
- 不支持递归创建节点
11.2 Apache curator
- Apache 开源项目
- 解决watcher的注册一次就失效的问题(永久存在)
- Api更加简单易用
- 提供更多的解决方案,并且实现简单:比如 分布式锁
- 提供常用的Zookeeper工具类
- 编码风格更简洁
11.3 curator之nodeCache一次注册N次监听
final NodeCache nodeCache = new NodeCache(cto.client, nodePath);
// buildInitial : 初始化的时候获取node的值并且缓存
nodeCache.start(true);
if (nodeCache.getCurrentData() != null) {
System.out.println("节点初始化数据为:" + new String(nodeCache.getCurrentData().getData()));
} else {
System.out.println("节点初始化数据为空...");
}
nodeCache.getListenable().addListener(new NodeCacheListener() {
public void nodeChanged() throws Exception {
if (nodeCache.getCurrentData() == null) {
System.out.println("空");
return;
}
String data = new String(nodeCache.getCurrentData().getData());
System.out.println("节点路径:" + nodeCache.getCurrentData().getPath() + "数据:" + data);
}
});
11.4 Watcher统一配置
分布式环境中,可以通过zookeeper的watcher机制对集群环境中所有的节点做统一的更新(比如降级开关,如果mq集群挂了,触发开关进行降级,此时通过watcher机制同步通知到集群环境中所有应用)