目录
前置知识
1. 基础命令
未知指令:
ls:
create:
zookeeper中节点有四种类型,分别是:
1. 持久节点(Persistent Node)
2. 临时节点(Ephemeral Node)
3. 持久顺序节点(Persistent Sequential Node)
4. 临时顺序节点(Ephemeral Sequential Node)
set:
get:
delete:
deleteall:
stat:
2. 节点监控
3. 权限控制
world:
ip:
auth:
digest:
前置知识
Zookeeper多主机集群搭建https://blog.csdn.net/dxh9231028/article/details/141052933?spm=1001.2014.3001.5501搭建完zookeeper集群后,就可以通过bin目录下的zkCli.sh可执行文件连接Zookeeper客户端执行下面的指令了。
1. 基础命令
未知指令:
任何一个非zookeeper指令都会让zookeeper客户端打印所有指令大全
ls:
zookeeper中key的保存是以类似于文件目录的结构保存的,而ls命令则是查看我们的创建的key
如图我创建了多个key,并且通过ls查看根目录下的字节点,以及用-R选项查看根目录下所有子孙节点。
create:
通过create可以创建一个key,不过要精细到具体路径,并且要确保父目录存在
zookeeper中节点有四种类型,分别是:
1. 持久节点(Persistent Node)
定义:持久节点是 ZooKeeper 默认的节点类型。当一个持久节点被创建后,即使创建它的客户端断开连接或会话结束,该节点仍然会保留在 ZooKeeper 中,直到它被显式地删除为止。
创建方式:create /path "data"
2. 临时节点(Ephemeral Node)
定义:当创建临时节点的客户端会话结束(如客户端断开连接或会话超时),该节点将自动被删除。
创建方式:create -e /path "data"
3. 持久顺序节点(Persistent Sequential Node)
定义:在创建持久顺序节点时,ZooKeeper 会在节点名称的末尾自动附加一个递增的序列号。如创建node,那么实际节点可能是node000001。
用途:这种节点通常用于分布式锁、任务队列等需要顺序保证的场景。
创建方式:create -s /path "data"
4. 临时顺序节点(Ephemeral Sequential Node)
定义:临时顺序结合了临时节点和顺序节点的特性。创建临时顺序节点时,ZooKeeper 会在节点名称末尾自动附加一个递增的序列号。并且当创建它的客户端会话结束时,节点也会自动删除。
用途:临时顺序节点通常用于实现分布式锁等需要顺序控制的场景,并且锁持有者会话结束后自动释放锁。
创建方式:create -e -s /path "data"
set:
通过set命令为某个节点设置数据
get:
获取某个节点数据
delete:
通过delete命令可以删除没有子节点的节点,而删除有子节点的节点时则会报错Node not empty
deleteall:
对于有子节点的节点可以通过deleteall命令进行删除
stat:
stat命令可以打印出当前节点的状态:
-
cZxid: 创建节点时的事务 ID,用于标识创建节点的那个具体事务。
-
ctime: 节点的创建时间,以 Unix 时间戳格式表示并转换为人类可读的日期时间格式。
-
mZxid: 最后一次修改该节点数据的事务 ID,用于标识最后修改节点数据的那个具体事务。
-
mtime: 节点数据最后一次被修改的时间,以 Unix 时间戳格式表示并转换为人类可读的日期时间格式。
-
pZxid: 最后一次更新该节点的子节点列表的事务 ID,用于标识上次对该节点的子节点列表进行修改的事务。
-
cversion: 子节点列表的版本号,表示该节点的子节点列表被修改的次数。
-
dataVersion: 节点数据的版本号,表示该节点数据被修改的次数。
-
aclVersion: 节点的 ACL(访问控制列表)版本号,表示该节点的 ACL 被修改的次数。
-
ephemeralOwner: 如果该节点是一个临时节点,
ephemeralOwner
表示创建该节点的会话 ID;如果该节点不是临时节点,则为 0。 -
dataLength: 节点数据的长度(以字节为单位),表示存储在该节点中的数据的大小。
-
numChildren: 该节点的子节点数量,表示这个节点下面有多少个直接子节点。
2. 节点监控
Zookeeper提供了对节点状态进行监控的功能,在3.5.0版本以前需要在获取节点信息的指令后面加一个true来开启对节点信息的监控,而3。5.0版本后则是使用-w选项来完成监控指令,这里我们讲最新的方式。
- get:get指令通过-w可以立刻获取到当前节点的数据,并且对该节点的数据变化进行监控。
- ls:ls指令通过-w可以获取其子节点目录,并且对当前节点子节点变化进行监控
- stat:stat指令通过-w可以获取当前节点状态信息,并且对当前节点的状态进行监控
需要注意的是,zookeeper的所有监控指令都是一次性的,他并没有提供可以一直监控的功能,所以如果需要一直对某个信息进行监控则需要在java代码中实现。
3. 权限控制
Zookeeper通过ACL(Access Control List,访问控制列表)来对节点的访问权限进行限制,每个 ACL 由三部分组成:
-
Scheme: 认证机制,用于定义如何验证用户身份。常见的 scheme 有 world、ip、auth、digest等。
-
ID: 标识符,用于标识特定的用户或客户端。ID 的具体内容取决于 scheme 的类型。例如,在 digest 机制中,ID 通常是用户名和密码的组合。
-
Permissions: 权限,用于定义可以执行的操作。权限包括以下几种:
- r: 读权限,允许读取节点的数据。
- w: 写权限,允许设置节点的数据。
- c: 创建权限,允许在该节点下创建子节点。
- d: 删除权限,允许删除该节点的子节点。
- a: 管理权限,允许设置节点的 ACL。
我们可以通过setAcl和getAcl指令来设置或获取某个节点的权限控制信息。
world:
world为节点默认的认证机制,也就是所有客户端都能随意的访问任何权限
ip:
ip是通过限制客户端ip来决定其是否具有当前节点的相关权限,其严格限制访问当前节点的客户端ip必须是目标ip,才被授予权限。
用其他主机连接目标ip客户端以及目标ip的主机通过zkCli.sh -server 127.0.0.1或zkCli.sh命令进行连接,都是不被授予权限的。但用目标ip的主机连接别的主机客户端却可以获得节点权限。
这说明具体使用哪个Zookeeper客户端是不重要的,只要源头是目标ip主机就可以。而使用回环地址Zookeeper则无法检测出是哪个ip在进行操作,所以zkCli.sh -server 127.0.0.1或zkCli.sh命令进行连接也无法获取权限。
当设置的目标ip为127.0.0.1时,虽然所有客户端的主机都能进行修改,但各个客户端连接的方式必须是zkCli.sh -server 127.0.0.1才会被授予权限,如果直接使用zkCli.sh,也不会被授予权限。
可以看到我通过回环地址连接当前主机的客户端,创建了一个当前主机ip才能访问的节点,但访问却没有权限,这说明和回环地址不能授予权限,即使是目标IP,于是我连接当前主机的ip。
连接当前主机的ip后,我继续获取,发现获取成功,然后继续连接集群中另一个zookeeper节点的ip
可以看到,即使是连接其他ip的zookeeper客户端,只要源头ip正确,则可以访问节点
我登陆另一台节点的主机,连接了目标ip主机的zookeeper客户都安,权限不足,这也在一次证实了源头ip决定了是否具有节点的权限,跟zookeeper客户端无关。
auth:
auth是通过认证信息来决定当前会话是否具有操作节点的权限。首先要创建一个认证信息,然后讲认证信息交给节点,当其他会话访问节点时会检测当前会话环境中是否有对应的认证信息,如果有才被允许访问。
首先通过addauth digest test:test创建认证信息,其中addauth是添加认证信息的指令,digest是认证机制(还有一个sasl机制,不常用,这里不讲),而两个test分别是账号和密码。 此时在当前会话中变存在了这样一条认证信息。
即使有账号和密码,认证信息也和用户毫无关系,zookeeper没有提供任何一种针对于用户的权限控制,所有权限控制都是针对于节点的,并且zookeeper也没有持久化存储用户的功能。
而现在创建的认证信息只是通过addauth命令临时存在当前会话中(后续想要操作目标节点,也需要再次执行这个指令),如果不在当前会话中将这条认证信息赋予节点,这条认证信息则会消失。
当前会话中可以随便操作目标节点,原因也是我们已经通过addauth指令在当前会话环境中创建了认证信息,如果我们关闭当前会话,重新连接客户端操作该节点,则会发现权限不足,需要冲洗调用addauth指令,使用争取的用户名和密码
然后在通过setAcl指令,使用auth认证机制 : test用户名 :权限,来讲认证信息存入节点中用于权限控制。但可以看到存入之后调用getAcl获取到的认证机制却是digest,这个下面说。
digest:
实际上auth和digest是同一种认证机制,都属于digest认证机制,两个操作也基本一致,如下图:
可以看到两个流畅大致类似,都是要创建认证信息,然后讲认证信息存入节点中,不过auth在设置时只需要指定用户名,而digest则需要在用户名后跟一串密文。
这个密文并不是密码单独的密文,而是 "账号:密码" 整体的密文,在命令行中可以使用如下命令获取
echo -n "账号:密码" | openssl dgst -binary -sha1 | openssl base64
在java中也可以通过zookeeper驱动依赖中DigestAuthenticationProvider类的generateDigest方法获取加密后的密文。
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
public class ZkDigestExample {
public static void main(String[] args) throws Exception {
String username = "dtest";
String password = "password123";
// 生成密文
String digest = DigestAuthenticationProvider.generateDigest(username + ":" + password);
// 输出密文
System.out.println(digest);
}
}
而在其他会话中对该节点进行操作的步骤则是完全一致,都是通过 addauth digest 账号:密码 指令来在当前会话环境中存入认证信息,就可以操作节点了。
auth和digest都是digest认证机制,两个在实际使用中区别很小(最起码我看起来是这样),我发现的唯一区别就是如果一个绘画环境中有多个相同用户名的认证信息,那么通过auth来给节点绑定认证信息则会全部绑定,而digest由于需要密码的参与,则不会导致全部绑定。