1 zookeeper几个关键的东西
1.1 数据结构-节点
/a/b/c 节点 包含了目录和文件的特性(名称类似目录,本身又类似文件携带数据)
1.2 节点分类
永久/临时|有序/无须
特点一:节点的创建必须一级一级的创建,如创建/a/b节点,需要先创建/a节点,再创建/a/b节点
特点二:节点的创建只能创建不存在的节点,不能重复,如已创建/a节点,再次创建/a节点会失败
特点三:有序节点的创建为自动赋予序号,如创建/a,实际创建的是/a00000001,这个序号是递增的,再创建/b,实际创建的是/b0000002,再次创建/a,实际创建的是/a0000003(临时节点的创建可以多次创建/a,因为实际创建的是/a+序号,没有重复)
特点四:每个节点都有版本号,新增时版本号为0,没有修改版本号递增
1.3 全局事务id
zk集群中,所有的写操作,leader都会生成一个有序的事务id,事务的执行是按照事务id的顺序来执行的
1.4 watcher
zk具有监控功能,可以监控节点的数据变化和节点删除,还可以监控子节点的增加和删除
1.5 zab协议
leader选举、恢复同步、原子广播-----保证了zk集群数据的一致性
2 Zookeeper常用的业务场景
zookeeper是一个分布式的数据一致性的解决方案。致力于为分布式应用一同一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调存储服务。
维护配置信息
分布式锁服务(临时有序节点)
集群管理
分布式唯一id(持久化有序节点)
2.1维护配置信息
把zookeeper作为一个配置中心
2.3 集群管理
[zk: localhost:2181(CONNECTED) 7] get /ns-1/tenant
cZxid = 0x6a0000000a
ctime = Wed Mar 27 09:56:44 CST 2019
mZxid = 0x6a0000000a
mtime = Wed Mar 27 09:56:44 CST 2019
pZxid = 0x6a0000000e
cversion = 2
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2
cZxid:数据节点创建时的事务 ID(zookeeper每一个写操作都会开启一个事务,而每个事务都会维护一个事务id。写操作包括节点创建、修改、删除)
ctime:数据节点创建时的时间
mZxid:数据节点最后一次更新时的事务 ID
mtime:数据节点最后一次更新时的时间
pZxid:数据节点的子节点最后一次被修改时的事务 ID
cversion:子节点的更改次数
dataVersion:节点数据的更改次数
aclVersion:节点的 ACL 的更改次数(当前的节点的权限列表被修改的次数)
ephemeralOwner:如果节点是临时节点,则表示创建该节点的会话的SessionID;如果节点是持久节点,则该属性值为 0
dataLength:数据内容的长度(单位是字节)
numChildren:数据节点当前的子节点个数
useradd zookeeper
passwd zookeeper//解压jdk
tar -xzvf jdk-8u131-linux-x64.tar.gz
// vim打开 .bash_profile文件
vi .bash_profile
// 文件中加入如下内容
JAVA_HOME=/home/zookeeper/jdk1.8.0_131
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
export PATH
// 使环境变量生效
. .bash_profile
// 敲如下命令,系统如图反馈说明安装成功
java -version
// 解压zookeeper
tar -xzvf apache-zookeeper-3.6.2.tar.gz
// 进入conf目录
cd /usr/local/programs/zookeeper/apache-zookeeper-3.6.2/conf
// 修改配置文件前先复制一份配置文件
cp zoo_sample.cfg zoo.cfg
// zookeeper根目录下新建data目录 -用于存放数据
mkdir data
// vi 修改配置文件中的dataDir
// 此路径用于存储zookeeper中数据的内存快照、及事物日志文件
dataDir=/usr/local/programs/zookeeper/apache-zookeeper-3.6.2/data
配置文件名称改为 zoo.cfg
进入bin目录
启动服务 ./zkServer.sh start
客户端连接:./zkCli.sh
5.6 新版 ZooKeeper 启动时一直报错
https://blog.csdn.net/peng2hui1314/article/details/107255142
5.6.1 错误
Starting zookeeper … FAILED TO START
5.6.2 原因
1)下载的版本问题(>= 3.5.5)
2)端口冲突问题(>=3.5.0)
5.7 下载的版本问题(>= 3.5.5)
实际上只要 >= 3.5.5 版本都会出现这种问题。
问题原因:下载了错误的版本文件,Zookeeper 从3.5.5后开始拆分为两个版本,而且他们的结构还很类似。
标准版本(Apache ZooKeeper x.y.z ),下载的文件名为:apache-zookeeper-x.y.z-bin.tar.gz
另一个是源码版本(Apache ZooKeeper x.y.z Source Release),下载的文件名为:apache-zookeeper-x.y.z.tar.gz
所以下载 Zookeeper 的时候要注意,应该下载第一个。
5.8 端口冲突问题(可能遇到)
在3.5.5版本及以上,Zookeeper 提供了一个内嵌的Jetty容器来运行 AdminServer,默认占用的是 8080端口,AdminServer 主要是来查看 Zookeeper 的一些状态,如果机器上有其他程序(比如:Tomcat)占用了 8080 端口,也会导致 Starting zookeeper … FAILED TO START 的问题。
该问题的错误日志如下:
org.apache.zookeeper.server.admin.AdminServer$AdminServerException: Problem starting AdminServer on address 0.0.0.0, port 8080 and command URL /commands
at org.apache.zookeeper.server.admin.JettyAdminServer.start(JettyAdminServer.java:176)
at org.apache.zookeeper.server.ZooKeeperServerMain.runFromConfig(ZooKeeperServerMain.java:153)
at org.apache.zookeeper.server.ZooKeeperServerMain.initializeAndRun(ZooKeeperServerMain.java:112)
at org.apache.zookeeper.server.ZooKeeperServerMain.main(ZooKeeperServerMain.java:67)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(QuorumPeerMain.java:140)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain.java:90)
Caused by: java.io.IOException: Failed to bind to /0.0.0.0:8080 //不能绑定8080端口
at org.eclipse.jetty.server.ServerConnector.openAcceptChannel(ServerConnector.java:346)
at org.eclipse.jetty.server.ServerConnector.open(ServerConnector.java:307)
at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:80)
at org.eclipse.jetty.server.ServerConnector.doStart(ServerConnector.java:231)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
at org.eclipse.jetty.server.Server.doStart(Server.java:385)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
at org.apache.zookeeper.server.admin.JettyAdminServer.start(JettyAdminServer.java:167)
... 5 more
Caused by: java.net.BindException: Address already in use //地址正在被使用
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at org.eclipse.jetty.server.ServerConnector.openAcceptChannel(ServerConnector.java:342)
... 12 more
Unable to start AdminServer, exiting abnormally
2020-07-17 21:07:30,759 [myid:] - INFO [main:ZKAuditProvider@42] - ZooKeeper audit is disabled.
2020-07-17 21:07:30,760 [myid:] - ERROR [main:ServiceUtils@42] - Exiting JVM with code 4
可以通过以下几种方式去解决
1)如果不需要 AdminServer ,可以直接禁用:打开 zoo.cfg 配置文件,直接添加以下语句即可。
# 禁用 AdminServer 服务
admin.enableServer=false
2)如果想使用 AdminServer , 那么可以直接在 zoo.cfg 配置文件中修改端口号即可,比如让其绑定 9000。
# admin port
admin.serverPort=9000
6 常用操作命令
6.1 基础命令
./zkServer.sh start 启动zookeeper
./zkServer.sh status 查看zookeeper状态
./zkCli.sh 启动客户端进入会话
quit 结束当前会话- 也就是 ./zkCli.sh的会话结束了,需要重新./zkCli.sh新建会话
6.2 创建节点create
6.2.1 格式
create 命令用于创建节点并赋值
格式:create [-s] [-e] path data acl
[-s] [-e]:-s 和 -e 都是可选的,-s 代表顺序节点, -e 代表临时节点。
注意其中 -s 和 -e 可以同时使用的,并且临时节点不能再创建子节点。也就是不设置-s和-e时,创建的是持久化的无序节点
path:指定要创建节点的路径,比如 /runoob
data:要在此节点存储的数据
acl:可选,访问权限相关,默认是 world,相当于全世界都能访问
6.2.2 创建持久化无序节点示例
创建持久化有序节点,这里没有设置data,也就是null。有序节点的路径自动加上了一个序号
6.2.3 创建临时无序节点示例
临时节点的生命周期是当前会话。quit退出当前会话的话,临时节点会被删除
6.3获取节点的数据get
6.3.1格式
get path
6.3.2 获取无序节点示例
6.3.3获取有序节点示例
它的路径自动加上了一个序号
6.4 查看节点状态信息stat
6.4.1 格式
stat path [watch]
path:代表路径。
[watch]:对节点进行事件监听
6.4.2 示例
6.4.3 属性
节点各个属性如下表。其中一个重要的概念是 Zxid(ZooKeeper TransactionId-事务id),ZooKeeper 节点的每一次更改都具有唯一的 Zxid,且是递增的,如果 Zxid1 小于 Zxid2,则
Zxid1 的更改发生在 Zxid2 更改之前
ACL是和当前节点的权限的相关的一个属性
6.5 修改节点存储的数据set
6.5.1 格式
set path data [-v version]
path:节点路径
data:需要存储的数据
[version]:可选项,版本号(可用作乐观锁)。从创建一个节点开始,会为这个节点生成一个版本号,从0开始。每次对这个节点进行修改,版本号会+1
6.5.2 不加版本号示例
6.5.3 加上版本号示例
通过stat命令,看到当前data版本号时7
这里指定的版本号是15 所以修改失败
这里指定的版本号是7 所以修改成功
6.6 删除节点delete
6.6.1 格式
delete path [-v version]
path:节点路径
[version]:可选项,版本号(同 set 命令)
6.6.2 示例
当前data版本是8
版本错误,删除失败
版本正确,删除成功
再创建一个节点 /hadop/a
此时来删除/hadop,删除失败。也就是说,delete不能删除有子节点的节点
6.7 删除节点rmr(可删除带有子节点的节点)
这个命令被deleteall替代,不推荐使用
6.7.1 格式
rmr path
path:节点路径
6.8 删除节点deleteall(可删除带有子节点的节点)
6.8.1 格式
deleteall path
path:节点路径
6.8.2 示例
6.9 查看某个路径下目录列表ls
6.9.1 格式
ls path
6.9.2 示例
创建/a节点 创建/a/b节点
查看a节点下的目录
再创建节点/a/b/c
查看a节点下的目录,发现还是只有b节点。说明ls只能查看节点的子节点,不能查看子节点下的节点
6.10 查看某个路径下目录列表ls2
6.10.1 格式
ls2 path
6.10.2 示例
ls2命令和ls一样,也是查看节点的子节点,不能查看子节点下的节点,但是信息更加全面
再创建一个节点/a/bb ls2查看
7.监听器
7.1 zookeeper 事件监听机制
7.1.1 watcher概念
zookeeper提供了数据的发布/订阅功能,多个订阅者可同时监听某一特定主题对象,当该主题对象的自身状态发生变化时(例如节点内容改变、节点下的子节点列表改变等),会实时、主动通知所有订阅者zookeeper采用了Watcher机制实现数据的发布/订阅功能。该机制在被订阅对象发生变化时会异步通知客户端,因此客户端不必在Watcher注册后轮询阻塞,从而减轻了客户端压力。watcher机制实际上与观察者模式类似,也可看作是一种观察者模式在分布式场景下的实现方式。
7.1.2 watcher架构
Watcher实现由三个部分组成:Zookeeper服务端、Zookeeper客户端、客户端的ZKWatchManager对象
客户端首先将Watcher注册到服务端,同时将Watcher对象保存到客户端的Watch管理器中。当ZooKeeper服务端监听的数据状态发生变化时,服务端会主动通知客户端,接着客户端的Watch管理器会触发相关Watcher来回调相应处理逻辑,从而完成整体的数据发布/订阅流程
7.1.3 watch特性
watch是串行化执行的,也就是一个一个的watch执行,串行同步执行。
7.2 watch相关命令
7.2.1 get
1)格式
get path [watch] 或者 get [-s] [-w] path
使用get path [watch] 注册的监听器能够在节点内容发生改变的时候,向客户端发出通知。需要注意的是 zookeeper 的触发器是一次性的 (One-time trigger),即触发一次后就会立即失效
2)示例
开始监听get path [watch]
另一个客户端修改
此处收到事件通知
开始监听get -w path
另一个客户端修改
此处收到事件通知
7.2.2 stat
1)格式
stat path [watch] 或者 stat [-w] path
使用stat path [watch] 注册的监听器能够在节点状态发生改变的时候,向客户端发出通知。需要注意的是 zookeeper 的触发器是一次性的 (One-time trigger),即触发一次后就会立即失效
2)示例
开始监听stat path [watch]
另一个客户端修改
此处收到事件通知
开始监听stat-w path
另一个客户端修改
此处收到事件通知
7.2.3 ls\ls2 path [watch]
1)格式
ls\ls2 path [watch] 或者ls\ls2 -w path
使用ls path [watch] 或ls2 path [watch] 注册的监听器能够监听该节点下所有子节点的增加和删除操作
2)示例
7.3 监听器的应用
zookeeper可以作为配置中心来使用。监听器就可以对配置内容进行监听。当配置发生变化时,可以收到通知,做相应的处理。
8 ACL权限控制
8.1 概述
zookeeper 类似文件系统,client 可以创建节点、更新节点、删除节点,那么如何做到节点的权限的控制呢?zookeeper的access control list 访问控制列表可以做到这一点。
acl 权限控制,使用scheme:id:permission 来标识,主要涵盖 3 个方面:
1)权限模式(scheme):授权的策略
2)授权对象(id):授权的对象
3)权限(permission):授予的权限
zookeeper的acl权限控制的特性
1)zooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限
2)每个znode支持设置多种权限控制方案和多个权限
3)子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点
8.2 权限模式
采用何种方式授权
world:对所有用户授权(默认的)
ip:对指定ip用户授权
auth:对某个指定用户授权(用户:密码 密码可以是明文的)
digest:对某个指定用户授权(用户:密码 密码必须是加密的)
8.3 授权的对象
授权模式使用world:授权对象只有一种:anyone -登录zookeeper的所有人
授权模式使用ip:ip地址
授权模式使用auth:指定的用户
授权模式使用digest:指定的用户
8.4 授权的权限
create、delete、read、writer、admin也就是 增、删、改、查、管理权限,这5种权限简写为cdrwa,注意:这5种权限中,delete是指对子节点的删除权限,其它4种权限指对自身节点的操作权限
8.5 授权相关命令
getAcl 命令:获取某个节点的 acl 权限信息。
setAcl 命令:设置某个节点的 acl 权限信息。
addauth 命令:输入认证授权信息,注册时输入明文密码,加密形式保存
getAcl - 最开始默认是world:anyone
8.6 授权实例
1)world模式
2)ip模式
设置ip权限
远程登录zookeeper命令:./zkCli.sh -server ip
3)auth模式
添加用户(这个操作将用户user1加入了当前会话,当前会话可以访问user1的节点)
设置权限
获取权限
获取数据
qiut退出当前会话后,重新登录,获取数据,权限不足
再次添加用户
4)digest模式
设置权限,需要加上密码,且密码是密文
获取密文(账号user2 密码 user2)
echo -n user2:user2 | openssl dgst -binary -sha1 | openssl base64
结果:ExK4ZEpM5XR9l8dLA7B6b79kLIo=
设置权限(密码是密文)
获取权限,权限不足
添加用户(密码明文)
获取权限
5)多种授权模式
授权,多种授权用逗号隔开
添加用户
获取数据
8.7 超级管理员
echo -n super:admin | openssl dgst -binary -sha1 | openssl base64
生成结果
xQJmxLMiHGwaqBvst5y6rkB6HQs
nohup "$JAVA" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" \
"-Dzookeeper.log.file=${ZOO_LOG_FILE}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='kill -9 %p' \
这就是脚本中启动zookeeper的命令,默认只有以上两个配置项,我们需要加一个超管的配置项
"-
Dzookeeper.DigestAuthenticationProvider.superDigest=super:xQJmxLMiHGwaqBv
st5y6rkB6HQs="
那么修改以后这条完整命令变成了
nohup "$JAVA" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" \
"-Dzookeeper.log.file=${ZOO_LOG_FILE}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-
Dzookeeper.DigestAuthenticationProvider.superDigest=super:xQJmxLMiHGwaqBv
st5y6rkB6HQs=" \
-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='kill -9 %p' \
重启zookeeper ps-ef|grep zookeeper kill - 9 xxx 杀掉进程
之后启动zookeeper
创建节点/www
create /www
设置权限
setAcl /www auth:user3:cdrwa
获取数据,权限不足,添加超级管理员再获取