目前zookeeper的版本是3.6.0,同时增加了几个新特性,同时拥抱了Prometheus.
如果你还对zookeeper不了解的话,建议你认真地阅读这篇文章,我想你会有不少的收获。
zookeeper的特性
- 一致性: 数据一致性,数据是按照顺序分批入库的
- 原子性: 事务要么成功要么失败,不会局部化
- 单一视图: 客户端连接集群中的任一zk节点,数据都是一致的
- 可靠性: 每次对zk的操作状态都会保存在服务端
- 实时性: 客户端可以读取到zk服务端的最新数据
zookeeper工作方式
- zookeeper集群包含1个leader,多个follower
- 所有的follower都可提供读服务
- 所有的写做做都会被forward到leader
- client与server通过NIO通信
- 全局串行化所有的写操作
- 保证同一客户端的指令被FIFO执行
- 保证消息通知的FIFO
zookeeper单独安装
- 下载jdk文件和zookeeper的包到linux服务器上
- 解压java jdk安装包然后通过软连接到
/usr/local/jdk
- 解压zookeeper安装包到
/usr/local/zookeeper
- 配置环境变量
export JAVA_HOME=/usr/local/jdk
export ZOOKEEPER_HOME=/usr/local/zookeeper
export CLASSPATH=.:%JAVA_HOME%/lib/dt.jar:%JAVA_HOME%/lib/tool.jar
#export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$ZOOKEEPER_HOME/bin:$JAVA_HOME/bin
zookeeper配置文件说明
代码语言:javascript复制tickTime: ZooKeeper使用的基本时间单位(毫秒)。它用于做心跳,并且最小会话超时将是tickTime的两倍
initLimit:用于集群,允许从节点连接并同步到master节点的初始化连接时间,以tickTime的倍数来表示
syncLimit:用于集群,master主节点与从节点之间发送消息,请求和答应时间长度(心跳机制)
dataDir: 存储内存数据库快照的位置,存储事务日志的更新。
dataLogDir: 可以不配置,如果不配置的话就默认存储在数据目录同级目录下
clientPort: 连接服务器的端口,默认端口是2181
# zookeeper3.6.0集成了prometheus
metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
metricsProvider.httpPort=7000
metricsProvider.exportJvmInfo=true
zkCli之间session的特性
- 客户端与服务端之间的连接存在回话
- 每个回话都会可以设置一个超时时间
- 心跳结束,session则过期
- session过期,则这个session创建的临时节点znode则会被抛弃
- 心跳机制:客户端向服务端发送ping包请求
zookeeper命令
启动zk服务
代码语言:javascript复制zkServer.sh --config $ZOOKEEPER_HOME/config start/stop/status/restart
基础命令
zkcli get/list
- list 列出当前目录结构
- get 查看指定的路径的值
[zk: localhost:2181(CONNECTED) 9] get /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 # 当前子节点的版本号
dataVersion = 0 # 当前节点的数据版本号,修改会自加1
aclVersion = 0 # 当前权限版本,修改会自加1
ephemeralOwner = 0x0 #
dataLength = 0
numChildren = 1 # 子节点的数量
zkcli create
代码语言:javascript复制create [-s] [-e] path data acl
# 创建一个节点
[zk: localhost:2181(CONNECTED) 14] create /hanbao hanbao
Created /hanbao
[zk: localhost:2181(CONNECTED) 15] get /hanbao
hanbao
# 创建一个临时的节点
[zk: localhost:2181(CONNECTED) 16] create -e /hanbao/hanbao1 hanbao1
Created /hanbao/hanbao1
[zk: localhost:2181(CONNECTED) 17] get /hanbao/hanbao1
hanbao1
...
ephemeralOwner = 0x10000278d900001 # 是一个临时的节点
...
[zk: localhost:2181(CONNECTED) 18] get /hanbao
hanbao
...
numChildren = 1 # 有一个子节点
# 断开当前的session之后,等到心跳的时间过后。你会发现之前创建的临时节点已经没有了
[zk: localhost:2181(CONNECTED) 0] ls /hanbao # 尚在心跳期间
[hanbao1]
[zk: localhost:2181(CONNECTED) 1] get /hanbao
hanbao
...
[zk: localhost:2181(CONNECTED) 3] ls /hanbao
[]
# 创建有序节点数据
[zk: localhost:2181(CONNECTED) 6] create -s /hanbao/hanbao2 seq
Created /hanbao/hanbao20000000001
[zk: localhost:2181(CONNECTED) 7] create -s /hanbao/hanbao2 seq
Created /hanbao/hanbao20000000002
[zk: localhost:2181(CONNECTED) 8] create -s /hanbao/hanbao2 seq
Created /hanbao/hanbao20000000003
[zk: localhost:2181(CONNECTED) 9] ls /hanbao
[hanbao20000000003, hanbao20000000001, hanbao20000000002]
# 修改数据,同时我们使用乐观锁的情况下更新数据,在设置新的值的时候,我们指定在哪个版本的基础上进行设置数据,当我们在修改某一版本数据的时候如果还有人继续的修改此数据,就会有错误的产生
[zk: localhost:2181(CONNECTED) 29] set /hanbao30000000013 32 1 #同时会返回操作后的数据的元数据
...
dataVersion = 2
...
delete
代码语言:javascript复制delete /hanbao #如果当前的节点下面存在其他的子节点。那么就会报错
ls /hanbao
delte /hanbao/hanbao20000000003
zookeeper watcher
- 针对每一个节点的变化,都会有一个watcher
- 当监控的某个对象发生了变化,则触发watcher机制
- zK中的watcher是一次性的,触发后立即销毁
- 父节点,子节点增删改查都能触发其watcher
zookeeper watcher command
代码语言:javascript复制stat /test watch # 创建一个队/test的监控事件
[zk: localhost:2181(CONNECTED) 45] stat /test watch
Node does not exist: /test
[zk: localhost:2181(CONNECTED) 46] create /test data
WATCHER::
WatchedEvent state:SyncConnected type:NodeCreated path:/test
Created /test
[zk: localhost:2181(CONNECTED) 49] get /test/test1 watch
data1
cZxid = 0xbf
ctime = Wed Jul 03 23:23:51 EDT 2019
mZxid = 0xbf
mtime = Wed Jul 03 23:23:51 EDT 2019
pZxid = 0xbf
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 50] set /test/test1 789
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/test/test1
cZxid = 0xbf
ctime = Wed Jul 03 23:23:51 EDT 2019
mZxid = 0xc0
mtime = Wed Jul 03 23:26:09 EDT 2019
pZxid = 0xbf
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
常见的事件类型:
- type:NodeDataChanged
- type:NodeCreated
- type:NodeDeleted
注意这些事件一旦被触发了,就消失了,再次更新和删除数据的时候就不会触发watcher的事件了
zookeeper ACL权限控制
- 针对节点可以设置相关的读写等权限,目的是为了保障数据的安全性
- 权限可以指定不同的权限范围以及角色
ACL命令行
- getACL
- setACL
- addauth: 输入认证的的授权信息,输入的时候是明文信息,但是在zookeeper系统里存储的是加密的形式
ACL的构成
zk是通过schema:id:permissions构成,其中schema表示某种权限机制,id表示的是允许用户访问的ID,permission是权限组合的字符串
- schema
- world这种schema只有一个用户就是anyone.表示任何人都可以访问
- auth:代表认证用户。需要注册用户有权限就可以,形式auth:user:password:[permissions]
- digest:需要对密码加密才能访问,形式digest:username:BASE64(SHA1(password)):[permissions]
- ip:设置ip为指定的Ip地址,此时限制ip进行访问,比如ip:192.168.99.130:[permissions]
- suoper:代表超级管理员,拥有所有权限
auth与digest的区别就是前者是输入的明文密码,后者输入的是密文密码。如
代码语言:javascript复制setAcl /test auth:cloudnative:ecosystem:cdrwa
||
setAcl /test digest:cloudnative:BASE64(SHA1(ecosystem)):cdrwa
在通过addauth digest cloudnative:ecosystem后都能操作指定节点的权限
permissions的构成crdwa
- create #表示的是当前节点的子节点
- read # 表示对自身节点的读权限
- delete #表示对子节点的删除的权限
- admin # 管理员的权限
- write # 写权限
一些案例
代码语言:javascript复制[zk: localhost:2181(CONNECTED) 12] addauth digest test:test
[zk: localhost:2181(CONNECTED) 13] setAcl /home/suoper auth:test:test:cdrwa
Node does not exist: /home/suoper
[zk: localhost:2181(CONNECTED) 14] create /home/suoper suoperdata
Node does not exist: /home/suoper
[zk: localhost:2181(CONNECTED) 15] create /home/ homedata
Command failed: java.lang.IllegalArgumentException: Path must not end with / character
[zk: localhost:2181(CONNECTED) 16] create /home homedata
Created /home
[zk: localhost:2181(CONNECTED) 17] create /home/suoper suoperdata
Created /home/suoper
[zk: localhost:2181(CONNECTED) 18] setAcl /home/suoper auth:test:test:cdrwa
...
aclVersion = 1
[zk: localhost:2181(CONNECTED) 19] getAcl /home/suoper
'digest,'test:V28q/NynI4JI3Rk54h0r8O5kMug=
: cdrwa
当我们重新设置授权之后其密码是不会变化的
代码语言:javascript复制[zk: localhost:2181(CONNECTED) 21] setAcl /home/suoper auth:jack:jack:cdrwa
...
aclVersion = 2
[zk: localhost:2181(CONNECTED) 22] getAcl /home/suoper
'digest,'test:V28q/NynI4JI3Rk54h0r8O5kMug=
: cdrwa
[zk: localhost:2181(CONNECTED) 23] setAcl /home/suoper auth:jack::cdrwa
...
aclVersion = 3
[zk: localhost:2181(CONNECTED) 24] getAcl /home/suoper
'digest,'test:V28q/NynI4JI3Rk54h0r8O5kMug=
: cdrwa
四种认证方式使用
digest
代码语言:javascript复制[zk: localhost:2181(CONNECTED) 2] create /home/zookeeper data
Created /home/zookeeper
[zk: localhost:2181(CONNECTED) 3] setAcl /home/zookeeper digest:test:V28q/NynI4JI3Rk54h0r8O5kMug=:crwa
...
aclVersion = 1
[zk: localhost:2181(CONNECTED) 4] getAcl /home/zookeeper
Authentication is not valid : /home/zookeeper
[zk: localhost:2181(CONNECTED) 5] addauth digest test:test
[zk: localhost:2181(CONNECTED) 6] getAcl /home/zookeeper
'digest,'test:V28q/NynI4JI3Rk54h0r8O5kMug=
: crwa
ip
代码语言:javascript复制[zk: localhost:2181(CONNECTED) 8] create /names data
Created /names
[zk: localhost:2181(CONNECTED) 9] create /names/cloudnative namedata
Created /names/cloudnative
[zk: localhost:2181(CONNECTED) 10] setAcl /names/cloudnative ip:192.168.0.101:crwad
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
[zk: localhost:2181(CONNECTED) 11] getAcl /names/cloudnative
Authentication is not valid : /names/cloudnative
超级管理员密码的设置
- 修改zkServer.sh配置,增加suoper用户和密码。在zkServer.sh文件中找到nohup那行,然后修改一下为以下:
nohup "$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-Dzookeeper.DigestAuthenticationProvider.suoperDigest=test:V28q/NynI4JI3Rk54h0r8O5kMug="
-cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
以上的 DigestAuthenticationProvider
在源码中有一个这样的包名称,包含着一个suoperDigest加密的方法
- 重启zookeeper
root@99-129:/usr/local/zookeeper# bin/zkServer.sh --config conf restart
ZooKeeper JMX enabled by default
Using config: conf/zoo.cfg
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Stopping zookeeper ... STOPPED
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
- 如何获取suoper用户的密码
export ZK_CLASSPATH=/etc/zookeeper/conf/:/usr/hdp/current/zookeeper-server/lib/*:/usr/hdp/current/zookeeper-server/*
java -cp $ZK_CLASSPATH org.apache.zookeeper.server.auth.DigestAuthenticationProvider super:super123
OUTPUT:
super:super123->super:UdxDQl4f9v5oITwcAsO9bmWgHSI=
acl使用的场景
- 开发、测试、生产环境之间的隔离,开发者无权操作测试者的节点,只能看
- 生产环境上可以控制指定IP的服务可以访问相关的节点,防止混乱,但是不适用于那些使用动态IP的服务
zookeeper的四字命令
- 查看zookeeper的服务状态以及mode
root@99-129:/usr/local/zookeeper# echo stat | nc 192.168.99.129 2181 #注意需要在配置文件中开启四字命令
Zookeeper version: 3.6.0--b4c89dc7f6083829e18fae6e446907ae0b1f22d7, built on 02/25/2020 14:38 GMT
Clients:
/192.168.99.129:40650[0](queued=0,recved=1,sent=0)
Latency min/avg/max: 0/0.0/0
Received: 1
Sent: 0
Connections: 1
Outstanding: 0
Zxid: 0x400000000
Mode: follower
Node count: 5
- 检查zookeeper服务是否启动
# arok = are you ok? imok =