zookeeper客户端命令详解及ACL权限控制

1,637 阅读14分钟

「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战

客户端连接

命令:./bin/zkCli.sh -server [ip]:[port] 我本地连接如下(因为是本地也可以取消-server ip:port)

./bin/zkCli.sh -server 192.168.253.131:2181

image.png

客户端相关命令列表

通过help可以查看zookeeper提供给我们的所有命令,命令中带有[]的为非必填 image.png

命令介绍

close
关闭当前会话

connect host:port 重新连接指定Zookeeper服务

create [-s] [-e] [-c] [-t ttl] path [data] [acl]
创建节点

delete [-v version] path
删除节点,(不能存在子节点)

deleteall path
删除路径及所有子节点

setquota -n|-b val path
设置节点限额 -n 子节点数 -b 字节数

 listquota path
查看节点限额

delquota [-n|-b] path
删除节点限额

 get [-s] [-w] path
查看节点数据 -s 包含节点状态 -w 添加监听

ls [-s] [-w] [-R] path
列出子节点 -s状态 -R 递归查看所有子节点 -w 添加监听

printwatches on|off
是否打印监听事件

quit
退出客户端

 history
查看执行的历史记录

redo cmdno
重复 执行命令,history 中命令编号确定

removewatches path [-c|-d|-a] [-l]
删除指定监听

set [-s] [-v version] path data
设置值

setAcl [-s] [-v version] [-R] path acl
为节点设置ACL权限

getAcl [-s] path
查看节点权限

stat [-w] path
查看节点状态 -w 添加监听

sync path
强制同步节点

命令使用

ls 查看节点

注意:zookeeper默认为跟目录节点,所以查询的时候目录都是以"/"开头\

1、查看根目录节点

ls / image.png

2、查看下级节点

ls /zookeeper

image.png

3、以遍历的方式查看所有目录结构

ls -R /

image.png

4、监听目录及子目录修改

可以监控当前目录及子目录的变化(注意,此监听只监听目录加入/删除,对数据修改不监听)

ls -w /test

image.png

5、对所有子节点进行监听

ls -R -w /test2

image.png 注意:此时只对test2以及sub0/sub1/sub1进行一次监听,只要节点的监听被触发一次,后面就不会再进行监听了。

create 创建节点

create [-s] [-e] [-c] [-t ttl] path [data] [acl]
[-s]:创建节点后会有序号,并且序号递增
[-e]:创建临时节点
[-c]:创建容器节点
[-t]:创建ttl节点,可以指定超时时间,默认是禁用的,需要通过系统参数启用(-Dzookeeper.extendedTypesEnabled=true)
[data]:存储的数据
[acl]:权限方面\

1、基本命令

create /test
注意\color{red}{注意}:如果只有路径没有其他参数,创建的是持久化节点(持久化节点,在断开连接,甚至关闭服务的情况下,节点依然存在

image.png

2、创建节点并赋值数据

create /test2 jony

image.png

3、创建子节点

节点后面加上子节点即可

create /test2/sub0
ls -R /

image.png

4、创建带顺序的节点

用于去实现分布式锁,序号规则是10位,最大是2的33次方

create /fmally
create -s /fmally/jony-

image.png

5、创建临时节点
creatae -e /ephemeral fsfd
get /ephemeral

image.png

5-1、关闭客户端连接,临时节点sessionid过期

image.png 可以看到上面我们关闭客户端,下面查看日志窗口,提示对应临时节点的sessionid过期。
zookeeper日志在:/usr/local/{zookeeperhome}/logs里面
再次连接客户端,临时节点已经消失

image.png

需要注意的是
1、当客户端关闭之后,30秒内临时节点就会被删除,即使30秒客户端再次连接上线,这个节点也会被删除,因为之前的sessionid已经丢失。(实际上还是可以救活的,后面文章再进行介绍)
2、临时节点无法创建任意类型的子节点(如下)。

image.png

6、创建临时顺序节点
create /seq-ephemral //首先创建一个承载节点
create -s -e /seq-ephemral/sub0-

image.png

7、创建容器节点

容器节点可以作为一个父节点,表面和其他节点没啥区别,主要区别就是,当容器节点下创建子节点以后,当它下面的子节点全部被删除,60s后这个容器节点就会被删除

create -c /container
create /container/sbu0
create /container/sbu1
ls /container

image.png 删除所有子节点,并等待60s,查看

image.png

8、创建ttl节点

8-1、添加系统参数,并重启服务 首先进入bin目录打开zkServer.sh,接如下截图中添加命令

-Dzookeeper.extendedTypesEnabled=true

image.png 重启服务\

./bin/zkServer.sh stop conf/zoo.cfg 
./bin/zkServer.sh start conf/zoo.cfg

image.png 8-2、创建ttl节点
创建一个ttl节点,并设置5s过期(zookeeper后端会进行一个轮询,不一定是正好5s删除),值为good

create -t 5000 /ttl-node good

image.png

get查询节点

1、查看数据
get /test
get /test2

image.png 可以看到之前创建的test节点无数据,刚刚创建的test2节点有数据

2、添加监听,服务端可以实时感知,如有变化主动推送到客户端
get -w /test

注意:如果需要服务端实时监听并推送,需要客户端一直和服务端进行连接,并发送监命令,否则无法推送
场景1:客户端1发送监听,客户端2不发送监听

image.png 场景2:客户端1发送监听,客户端2也发送监听

image.png

注意\color{red}{*注意*}:
1、监听过一次变化之后就不再继续监听。
2、set 节点值即使值不变,也会触发监听事件,虽然值没变,但是节点属性变化了(事务id,更新时间)

set 修改节点数据

1、修改节点值

set /test xxx
get /test

image.png

delete删除节点

delete /test

image.png

deleteall 删除路径及所有子节点

deleteall /tests

removewatches 删除监听

removewatches path [-c|-d|-a] [-l]

1、先给节点添加一个监听

ls -w /test2

2、删除监听

removewatches /tests

image.png

节点属性

可以通过如下命令获得:
get -s /nodename或者stats nodename

get -s /ephemeral

image.png

属性解析

#创建节点的事物ID
cZxid = 0x385

#创建时间
ctime = Tue Sep 24 17:26:28 CST 2019

#修改节点的事物ID
mZxid = 0x385

#最后修改时间
mtime = Tue Sep 24 17:26:28 CST 2019

子节点变更的事物ID
pZxid = 0x385

#这表示对此znode的子节点进行的更改次数(不包括子节点)
cversion = 0

#数据版本,变更次数
dataVersion = 0

#权限版本,变更次数
aclVersion = 0

#临时节点所属会话ID(非临时节点,其他值都为0x0)
ephemeralOwner = 0x0

#数据长度
dataLength = 17

#子节点数(不包括子子节点)
numChildren = 0

Zookeeper ACLs权限控制

Zookeeper 的ACL 权限控制,可以控制节点的读写操作,保证数据的安全性,Zookeeper ACL 权限设置分为 3 部分组成,分别是:权限模式(Scheme)、授权对象(ID)、权限信息(Permission)。最终组成一条例如scheme:id:permission格式的 ACL 请求信息。下面我们具体看一下这 3 部分代表什么意思:

权限组成

Scheme(权限模式)

用来设置 ZooKeeper 服务器进行权限验证的方式。ZooKeeper 的权限验证方式大体分为两种类型:

一种是范围验证。所谓的范围验证就是说 ZooKeeper 可以针对一个 IP 或者一段 IP 地址授予某种权限。比如我们可以让一个 IP 地址为“ip:192.168.0.110”的机器对服务器上的某个数据节点具有写入的权限。或者也可以通过“ip:192.168.0.1/24”给一段 IP 地址的机器赋权。

另一种权限模式就是口令验证,也可以理解为用户名密码的方式。在 ZooKeeper 中这种验证方式是 Digest 认证,而 Digest 这种认证方式首先在客户端传送“username:password”这种形式的权限表示符后,ZooKeeper 服务端会对密码 部分使用 SHA-1 和 BASE64 算法进行加密,以保证安全性。

还有一种Super权限模式, Super可以认为是一种特殊的 Digest 认证。具有 Super 权限的客户端可以对 ZooKeeper 上的任意数据节点进行任意操作。

授权对象(ID)

授权对象就是说我们要把权限赋予谁,而对应于 4 种不同的权限模式来说,如果我们选择采用 IP 方式,使用的授权对象可以是一个 IP 地址或 IP 地址段;而如果使用 Digest 或 Super 方式,则对应于一个用户名。如果是 World 模式,是授权系统中所有的用户。

权限信息(Permission)

权限就是指我们可以在数据节点上执行的操作种类,如下所示:在 ZooKeeper 中已经定义好的权限有 5 种:

数据节点(c: create)创建权限,授予权限的对象可以在数据节点下创建子节点
数据节点(w: wirte)更新权限,授予权限的对象可以更新该数据节点;
数据节点(r: read)读取权限,授予权限的对象可以读取该节点的内容以及子节点的列表信息;
数据节点(d: delete)删除权限,授予权限的对象可以删除该数据节点的子节点
数据节点(a: admin)管理者权限,授予权限的对象可以对该数据节点体进行 ACL 权限设置。

权限相关命令

getAcl:获取某个节点的acl权限信息
setAcl:设置某个节点的acl权限信息
addauth: 输入认证授权信息,相当于注册用户信息,注册时输入明文密码,zk将以密文的形式存储

取消ACL权限校验: 可以通过系统参数zookeeper.skipACL=yes进行配置,默认是no,可以配置为true, 则配置过的ACL将不再进行权限检测

生成授权ID的两种方式

方式一 代码生成ID\

@Test
public void generateSuperDigest() throws NoSuchAlgorithmException {
    String sId = DigestAuthenticationProvider.generateDigest("gj:test");
    System.out.println(sId);//  gj:X/NSthOB0fD/OT6iilJ55WJVado=
}

方式二 在xshell 中生成
echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64

我们创建一个用户为jony,密码为111111

image.png

授权

通过秘钥授权

方式一 节点创建的同时设置ACL\

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

# digest:加密;最后一个参数代表哪些权限,权限类型在上面有
create /jony-node myname digest:jony:U54SpOkCB30hqXUXNdfdldolTKw=:rw

授权后,只有指定的用户才能访问,需要先登录指定用户,下边有讲如何添加授权信息进行登录\

方式二 或者用setAcl 设置
setAcl /zk-node  digest:jony:X/U54SpOkCB30hqXUXNdfdldolTKw=:rw

添加授权信息后,不能直接访问,直接访问将报如下异常

get /jony-node

image.png

授权以后,访问之前需要添加授权信息才能访问
addauth digest jony:111111
get /jony-node 

image.png

auth 明文授权

使用之前需要先addauth digest username:password 注册用户信息,后续可以直接用明文授权
如:

addauth digest jony:111111
create /node-1 node1data auth:jony:111111:rw
# 这时jony用户授权信息会被zk保存,可以认为当前的授权用户为jony
get /node-1
node1data

image.png 通过getAcl /node-1 也可以看到节点的权限信息
退出登录信息,重新登录再次查看节点
只有刚刚登录授权创建的用户,才可以看到对应的节点数 image.png

ip授权

setAcl /node-ip ip:192.168.109.128:rw
create /node-ip data ip:192.168.109.128:cdwra

多个指定IP可以通过逗号分隔, 如 setAcl /node-ip ip:IP1:rw,ip:IP2:a

Super 超级管理员模式

这是一种特殊的Digest模式, 在Super模式下超级管理员用户可以对Zookeeper上的节点进行任何的操作。
需要在启动了上通过JVM 系统参数开启:

DigestAuthenticationProvider中定义(super指的是用户名)
-Dzookeeper.DigestAuthenticationProvider.superDigest=super:<base64encoded(SHA1(password))
1、先生成秘钥

image.png

2、修改zkServer.sh 添加授权
-Dzookeeper.DigestAuthenticationProvider.superDigest=jony6:wedevHq8q39Io1hK7s13GKaiTvU=

image.png

3、重启服务登录访问
get /node-1
addauth digest jony6:666
get /node-1

image.png 可以看到登录超级管理员之后就可以查看所有节点了

Acl权限说明

image.png 通过getAcl /可以看到根目录是所有用户都可以访问
通过getAcl /node-1可以看到只有jony秘钥方式访问
通过getAcl /node-2可以看到jony和jony1秘钥访问访问\

acl权限设置
ACL全称为Access Control List(访问控制列表),用于控制资源的访问权限。ZooKeeper使用ACL来控制对其znode的防问。基于scheme:id:permission的方式进行权限控制。scheme表示授权模式、id模式对应值、permission即具体的增删改权限位。
scheme:认证模型

方案描述
world开放模式,world表示全世界都可以访问(这是默认设置)
ipip模式,限定客户端IP防问
auth用户密码认证模式,只有在会话中添加了认证才可以防问
digest与auth类似,区别在于auth用明文密码,而digest 用sha-1+base64加密后的密码。在实际使用中digest 更常见。

permission权限位

权限位权限描述
cCREATE可以创建子节点
dDELETE可以删除子节点(仅下一级节点)
rREAD可以读取节点数据及显示子节点列表
wWRITE可以设置节点数据
aADMIN可以设置节点访问控制列表权限

acl 相关命令:

命令使用方式描述
getAclgetAcl 读取ACL权限
setAclsetAcl 设置ACL权限
addauthaddauth 添加认证用户

world权限示例
语法: setAcl world:anyone:<权限位>
注:world模式中anyone是唯一的值,表示所有人

1. 查看默认节点权限:

创建一个节点
create -e /testAcl

查看节点权限
getAcl /testAcl

返回的默认权限表示 ,所有人拥有所有权限。
'world,'anyone: cdrwa

修改默认权限为 读写

设置为rw权限 
setAcl /testAcl world:anyone:rw

可以正常读
get /testAcl

无法正常创建子节点
create -e /testAcl/t "hi"

返回没有权限的异常
Authentication is not valid : /testAcl/t

IP权限示例:
语法: setAcl ip:<ip地址|地址段>:<权限位>

auth模式示例:
语法: 
1. setAcl auth:<用户名>:<密码>:<权限位>

2. addauth digest <用户名>:<密码>

digest 权限示例:
语法: 

1. setAcl digest :<用户名>:<密钥>:<权限位>

2. addauth digest <用户名>:<密码>

注1:密钥 通过sha1与base64组合加密码生成,可通过以下命令生成

echo -n <用户名>:<密码> | openssl dgst -binary -sha1 | openssl base64

注2:为节点设置digest 权限后,访问前必须执行addauth,当前会话才可以防问。

1. 设置digest 权限

#先 sha1 加密,然后base64加密

echo -n jony:123456 | openssl dgst -binary -sha1 | openssl base64

#返回密钥

2Rz3ZtRZEs5RILjmwuXW/wT13Tk=

#设置digest权限

setAcl /jony digest:jony:2Rz3ZtRZEs5RILjmwuXW/wT13Tk=:cdrw

查看节点将显示没有权限

#查看节点

get /jony

#显示没有权限访问

org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /jony

给当前会话添加认证后在次查看

#给当前会话添加权限帐户

addauth digest jony:123456

#在次查看

get /jony

#获得返回结果

hello word

ZooKeeper 内存数据和持久化

Zookeeper数据的组织形式为一个类似文件系统的数据结构,而这些数据都是存储在内存中的,所以我们可以认为,Zookeeper是一个基于内存的小型数据库,内存数据结构如下:

public class DataTree {
   //参数String指的是路径,DataNode指的是节点数据
    private final ConcurrentHashMap<String, DataNode> nodes =
        new ConcurrentHashMap<String, DataNode>();
        
    private final WatchManager dataWatches = new WatchManager();
    private final WatchManager childWatches = new WatchManager();

DataNode 是Zookeeper存储节点数据的最小单位

public class DataNode implements Record {
    byte data[];//用来放业务数据的
    Long acl;
    public StatPersisted stat;//状态信息
    private Set<String> children = null;//子节点信息

事务日志

针对每一次客户端的事务操作,Zookeeper都会将他们记录到事务日志中,当然,Zookeeper也会将数据变更应用到内存数据库中。我们可以在zookeeper的主配置文件zoo.cfg 中配置内存中的数据持久化目录,也就是事务日志的存储路径 dataLogDir. 如果没有配置dataLogDir(非必填), 事务日志将存储到dataDir (必填项)目录,

我这边日志如下: image.png Zookeeper进行事务日志文件操作的时候会频繁进行磁盘IO操作,事务日志的不断追加写操作会触发底层磁盘IO为文件开辟新的磁盘块,即磁盘Seek。因此,为了提升磁盘IO的效率,Zookeeper在创建事务日志文件的时候就进行文件空间的预分配- 即在创建文件的时候,就向操作系统申请一块大一点的磁盘块。这个预分配的磁盘大小可以通过系统参数 zookeeper.preAllocSize 进行配置。

事务日志文件名为: log.<当时最大事务ID>,应为日志文件时顺序写入的,所以这个最大事务ID也将是整个事务日志文件中,最小的事务ID,日志满了即进行下一次事务日志文件的创建

查看事务日志

zookeeper提供了格式化工具可以进行数据查看事务日志数据 org.apache.zookeeper.server.LogFormatter

cd /usr/local/apache-zookeeper-3.6.3-bin/lib/
java -classpath .:slf4j-api-1.7.25.jar:zookeeper-3.6.3.jar:zookeeper-jute-3.6.3.jar org.apache.zookeeper.server.LogFormatter /usr/local/apache-zookeeper-3.6.3-bin/data/version-2/log.1

在执行上面命令的时候,需注意本机安装的目录以及zookeeper的版本
执行结果:

image.png 从左到右分别记录了操作时间,客户端会话ID,CXID,ZXID,操作类型,节点路径,节点数据(用#+ascii 码表示),节点版本。

快照数据

数据快照用于记录Zookeeper服务器上某一时刻的全量数据,并将其写入到指定的磁盘文件中。

可以通过配置snapCount配置每间隔事务请求个数,生成快照,数据存储在dataDir 指定的目录;

可以通过如下方式进行查看快照数据( 为了避免集群中所有机器在同一时间进行快照,实际的快照生成时机为事务数达到 [snapCount/2 + 随机数(随机数范围为1 ~ snapCount/2 )] 个数时开始快照)

查看快照数据

zookeeper提供了格式化工具可以进行数据查看快照日志数据 org.apache.zookeeper.server.SnapshotFormatter

有了事务日志,为啥还要快照数据? 快照数据主要时为了快速恢复,事务日志文件是每次事务请求都会进行追加的操作,而快照是达到某种设定条件下的内存全量数据。所以通常快照数据是反应当时内存数据的状态。事务日志是更全面的数据,所以恢复数据的时候,可以先恢复快照数据,再通过增量恢复事务日志中的数据即可。