ZooKeeper 是一个开源(遵循 Apache License 2.0 协议)的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务。 分布式应用程序可以基于 ZooKeeper 实现数据发布与订阅、统一命名服务、统一配置管理、分布式协调与通知、集群管理、分布式锁、分布式队列等功能。
本方案基于 CentOS8 系统设计,建议在 RedHat/CentOS 系统中使用。
目录
1.技术评估
-- 1.1. ZooKeeper 的特性
-- 1.2. ZooKeeper 的集群角色
-- 1.3. ZooKeeper 的核心概念
-- 1.4. ZooKeeper 的应用场景
2.集群部署拓扑图
3.单点安装和配置
4.集群化配置
5.zkCli 客户端
6.Java 项目集成
1.技术评估
1.1. ZooKeeper 的特性
ZooKeeper 一般以集群的方式对外提供服务,一个集群包含多个节点,每个节点对应一台部署 ZooKeeper 程序的服务器,所有的节点共同对外提供服务,整个集群环境对分布式数据一致性提供了全面的支持。
1、顺序一致性
对于来自客户端的每个更新请求,ZooKeeper 都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序,最终将会严格按照其发送顺序进入 ZooKeeper 中。
2、数据一致性
无论客户端连接到 ZooKeeper 集群中哪个节点,所看到的服务端模型都是一致的,不可能出现两种不同的数据状态,因为 ZooKeeper 集群中每个节点之间会进行数据同步。
3、原子性
所有请求的响应结果在整个分布式集群环境中具备原子性。既是要么整个集群中所有节点都成功的处理了某个请求,要么就都没有处理,绝不会出现集群中一部分节点处理了某一个请求,而另一部分节点没有处理的情况。
4、可靠性
一旦服务端数据的状态发送了变化,就会立即存储起来,除非此时有另一个请求对其进行了变更,否则数据一定是可靠的。
5、实时性
当某个请求被成功处理后,客户端最终一定能从服务端上读取到最新的数据状态,即 ZooKeeper 保证数据的最终一致性。
6、高性能
ZooKeeper 将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,尤其适用于以读为主的应用场景。
7、高可用
ZooKeeper 一般以集群的方式对外提供服务,一般 3 ~ 5 个节点就可以组成一个可用的 ZooKeeper 集群,每个节点都会在内存中维护当前的节点状态,并且每个节点之间都相互保持着通信。只要集群中超过半数的节点能够正常工作,整个集群就能够正常提供服务。
1.2. ZooKeeper 的集群角色
1、Leader(领导者)
集群通过选举从所有的节点中选举一个节点作为 "Leader" 节点, "Leader" 节点为客户端提供读和写服务,是整个集群工作机制的核心,主要工作:
- 事务请求的唯一调度者和处理者,保证集群事务处理的顺序性。
- 集群内部各服务器的调度者。
2、Follower(跟随者)
集群中的 "Follower" 节点的主要工作:
- 参与 "Leader" 节点的选举。
- 处理客户端非事务请求 - 即读服务。
- 转发事务请求给 "Leader" 节点。
3、Observer(观察者)
集群中的 "Observer" 节点是 ZooKeeper 自 3.3.0 版本开始引入的一个全新的集群角色,主要工作与 "Follower" 节点基本是一致,唯一的区别是不参与 "Leader" 节点的选举, "Observer" 节点能够在不影响写性能的情况下提升集群的读性能。
1.3. ZooKeeper 的核心概念
1、ZNode(数据节点)
ZooKeeper 使用一个树状的内存模型,类似文件系统,这些目录与文件系统称为 "ZNode",ZNode 是 ZooKeeper 中最小的数据单元,每个 ZNode 上可以保存数据,还可以挂载子节点,构成了一个层次化的命名空间。
1)ZNode 存储结构
ZooKeeper 使用斜杠【/】分割的路径表示 ZNode 路径,斜杠【/】表示根节点。如下图:
2)ZNode 的类型
ZooKeeper 提供四种类型的 ZNode,用于满足不同场景的使用需求:
Persistent(持久节点):默认节点。该类型的 ZNode 被创建后,需要通过触发 “删除” 指令主动操作才能被清除;可以创建子节点。
Persistent Sequential(持久顺序节点):该类型的 ZNode 被创建后,名称带有自增数字后缀,该后缀标识创建的顺序;需要通过触发 “删除” 指令主动操作才能被清除;可以创建子节点。
Ephemeral(临时节点):该类型的 ZNode 被创建后,在当前会话结束后会被自动删除;不能创建子节点。
Ephemeral Sequential(临时顺序节点):该类型的 ZNode 被创建后,名称带有自增数字后缀,在当前会话结束后会被自动删除;不能创建子节点。
3) ZNode 的权限
ZooKeeper 通过 ACL(Access Contro List)机制在保障 ZNode 的数据安全,使用【scheme:id:Permission】的标记对 ZNode 进行权限标记,标记含义如下:
- scheme:定义授权策略
- id:定义授权对象
详细说明如下:
scheme(授权策略标识) | 授权策略说明 | id(授权对象形式) |
---|---|---|
ip | 指定的客户端 IP 地址或 IP 地址段 。 | 如:"192.168.0.1" 或者 "192.168.0.0/24" |
digest | 指定的用户名/口令。 | 一般采用【username:BASE64(SHA-1(USERNAME:PASSWORD))】的形式,如:"zk:Y2ViYThmY2JjOT..."。 |
world | 默认权限。对所有客户端开放。 | 使用静态权限标识 "world:anyone"。 |
super | 超级用户能够对任意 ZNode 进行任何操作。 | 一般采用【username:BASE64(SHA-1(USERNAME:PASSWORD))】的形式,如:"zk:Y2ViYThmY2JjOT..."。 |
- permission:定义授予操作权限。详细说明如下:
权限标识 | 简写 | 权限说明 |
---|---|---|
CREATE | c | 可以创建子节点 |
DELETE | d | 可以删除子节点(仅下一级节点) |
READ | r | 可以读取节点数据及显示子节点列表 |
WRITE | w | 可以设置节点数据 |
ADMIN | a | 可以设置节点访问控制列表权限 |
4)ZNode 的状态
ZNode 节点除了存储数据内容以外,还会自动存储节点的状态,属性如下:
属性 | 说明 |
---|---|
cZxid | ZNode 创建时的事务 ID。 |
ctime | ZNode 创建时的时间。 |
mZxid | ZNode 最后一次更新时的事务 ID。 |
mtime | ZNode 最后一次更新时的时间。 |
pZxid | ZNode 的子节点列表最后一次修改时的事务 ID,只有子节点列表变更时才会更新这个属性的值。 |
dataVersion | ZNode 的数据内容变更版本号。ZNode 创建时为属性值为 "0",每次更新数据内容时属性值 "+1",无论内容是否发生实际变更。 |
cVersion | ZNode 的子节点列表变更版本号。属性值为子节点列表的更新次数。 |
aclVersion | ZNode 的 ACL 权限变更版本号。属性值为 ZNode 的 ACL 信息变更次数。 |
ephemeralOwner | 创建临时 ZNode 的 SessionID,持久节点这个属性的值是常量 "0"。 |
dataLength | ZNode 的数据内容长度。 |
numChildren | ZNode 的子节点数量。 |
2、Watcher(数据变更通知)
Watcher 机制实现分布式数据的发布/订阅功能。ZooKeeper 允许客户端向服务器注册一个 Watcher 监听,当服务器的指定事件触发了这个 Watcher,就会主动向指定客户端发送一个事件通知。
3、Session(会话)
Session 是客户端和服务器之间的一个 TCP 长连接。
1)Session 的状态
会话在整个生命周期中,会在不同的会话转态之间进行切换,状态如下:
状态 | 说明 |
---|---|
CONNECTING | 连接中。当客户端开始创建 ZooKeeper 连接时,此时会话状态为 "CONNECTING"。 |
CONNECTED | 已连接。当客户端连接 ZooKeeper 节点成功后,此时会话状态为 "CONNECTED"。 |
RECONNECTING | 重新连接中。当客户端与 ZooKeeper 节点连接异常断开时,会尝试自动重连,此时会话状态为 "RECONNECTING"。 |
RECONNECTED | 已重新连接。当客户端重连连接 ZooKeeper 节点成功后,此时会话状态为 "RECONNECTED"。 |
CLOSE | 关闭连接。当客户端会话超时、权限检查失败或主动退出后,此时会话状态为 "CLOSE"。 |
2)Session 的属性
Session 是 ZooKeeper 中的会话实体,代表了一个客户端会话,其包含 4 个属性:
属性 | 说明 |
---|---|
sessionID | 会话唯一标识。每次客户端创建会话时,ZooKeeper 会为其分配一个全局唯一的 sessionID。 |
timeOut | 会话超时时间,客户端创建会话时传递。 |
tickTime | 下次会话超时时间点,为了便于 ZooKeeper 对会话管理,设置值接近于当前时间+TimeOut,是一个 13 位的 long 型数据。 |
isClosing | 标记会话是否已关闭。 |
3)Session 的心跳检测
为了保证客户端会话的有效性,客户端会在会话超时时间范围内向服务器发送PING请求来保持会话的有效性,即心跳检测。服务器接收到客户端的这个心跳检测,就会重新激活对应的客户端会话。
4)Session 的清理
当客户端和服务器之间网络连接断开,客户端会自动进行反复的重连,直到最终成功连接上 ZooKeeper 节点。在会话超时时间内重新连接上,被视为重连成功。在会话超时时间外重新连接上,此时服务器已经进行了会话清理,但客户端不知道会话已经失效,重新连接服务器会告诉客户端会话已失效,被视为非法会话。
1.4. ZooKeeper 的应用场景
ZooKeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,ZooKeeper 就将负责通知已经在 ZooKeeper 上注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式。
1、统一命名服务(Name Service)
分布式应用中,通常需要有一套完整的命名规则,既能够产生唯一的名称又便于人识别和记住,通常情况下用树形的名称结构是一个理想的选择,树形的名称结构是一个有层次的目录结构,既对人友好又不会重复。 ZooKeeper 将有层次的目录结构关联到一定资源上,但是 ZooKeeper 的 Name Service 更加是广泛意义上的关联,也许并不需要将名称关联到特定资源上,你可能只需要一个不会重复名称,就像数据库中产生一个唯一的数字主键一样。
ZooKeeper 已内置 Name Service 功能,只需要调用 ZooKeeper 的 API 就能实现。例如:调用 create 接口就可以很容易创建一个目录节点。
2、统一配置管理(Configuration Management)
配置的管理在分布式应用环境中很常见,例如:同一个应用系统需要部署多套程序副本共同运行,应用系统的某些配置项是相同的,当这些相同的配置项发生变化时,就必须逐个修改每个程序副本。
ZooKeeper 将配置信息保存在 ZNode 中,所有使用这些配置的程序副本监控这个 ZNode ,一旦配置信息发生变化,所有的程序副本都会收到 ZooKeeper 的通知,然后从 ZooKeeper 中获取最新的配置。
3、集群管理(Group Membership)
在多个成员组成一个服务集群时,必须有一个 Leader 收集当前集群中每个节点的服务状态,当有成员退出集群或者不能提供服务时,或有新的成员加入时, Leader 做出调整重新分配服务策略。
1)成员管理
ZooKeeper 创建一个用于成员管理的 Group ZNode ,在每个成员加入集群时,在这个 Group ZNode 下创建一个 Ephemeral 类型的 Member ZNode ,然后让 Leader 去监控 Group ZNode 的子节点列表的变化情况。
当集群成员退出集群或不能提供服务时,对应的 Member ZNode 会自动删除,触发 Group ZNode 子节点列表变更事件,集群的 Leader 会收到 ZooKeeper 的通知,然后进行处理。
2)Leader 选举
ZooKeeper 创建一个用于 Leader 选举的 Group ZNode ,在每个成员加入集群时,在这个 Group ZNode 下创建一个 Ephemeral Sequential 类型的 Candidate ZNode ,然后让所有集群成员去监控 Group ZNode 的子节点列表的变化情况。
当集群成员退出集群或不能提供服务时,对应的 Candidate ZNode 会自动删除,触发 Group ZNode 子节点列表变更事件,集群成员收到 ZooKeeper 的通知,验证最小编号的 Candidate ZNode 是否是当前的 Leader,如果不是,则将最小编号的 Candidate ZNode 对应的集群节点提升为新的 Leader。
4、共享锁(Locks)
ZooKeeper 创建一个用于共享锁管理的 Locks ZNode,当应用系统发起请求时,在这个 Locks ZNode 下创建一个 Ephemeral Sequential 类型的 Lock ZNode,然后监控 Locks ZNode 的子节点列表的变化情况。
当其他应用释放锁后,对应的 Lock ZNode 会自动删除,触发 Locks ZNode 子节点列表变更事件,应用系统收到 ZooKeeper 的通知,验证最小编号的 Lock ZNode 是否是自身创建的,如果是,则说明它获得了这个锁,当处理完成后,删除这个 Lock ZNode 来释放锁。
5、队列管理(Queues)
ZooKeeper 可以处理两种类型的队列:
- 当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。
- 队列按照 FIFO 方式进行入队和出队操作,实现生产者和消费者模型。
1)同步队列:
ZooKeeper 创建一个用于队列管理的 Queues ZNode,当成员加入前,首先检查 Queues ZNode 下是否存在Start ZNode,如果不存在,则在 Queues ZNode 下创建 Ephemeral Sequential 类型的 Member ZNode,然后监控 Queues ZNode 的子节点列表的变化情况。
当 Queues ZNode 的子节点列表满足队列成员数量上限时(也就是说成员已聚齐),则在 Queues ZNode 下创建 Start ZNode,创建后就不会有新的 Member ZNode 加入了,这时应用处理队列中的数据,并在处理结束后,删除 Start ZNode。
2)FIFO 队列:
ZooKeeper 创建一个用于队列管理的 Queues ZNode,当成员加入时,在这个 Queues ZNode 下创建一个 Sequential 类型的 Member ZNode,然后监控 Queues ZNode 的子节点列表的变化情况。
当 Queues ZNode 的子节点列表不为空时,处理最小编号的 Member ZNode。
2.集群部署拓扑图
网络资源规划:
ZooKeeper Server 节点
节点名 | 主机名 | IP 地址 | 程序 | 操作系统 |
---|---|---|---|---|
ZooKeeper Server-1 | zookeeper1 | 192.168.0.21:2181 | zookeeper | CentOS8 |
ZooKeeper Server-2 | zookeeper2 | 192.168.0.22:2181 | zookeeper | CentOS8 |
ZooKeeper Server≥3 | zookeeper3 | 192.168.0.23:2181 | zookeeper | CentOS8 |
3.单点安装和配置
以 "ZooKeeper Server-1" 节点为例:
注意:安装 ZooKeeper 前,应确保系统已经正确安装配置 JDK 。如何安装配置 JDK,请阅读文件《RedHat/CentOS8 安装配置 OracleJDK 8 和 OpenJDK 1.8》【https://www.jianshu.com/p/208cc5b8688b】
1、打开 ZooKeeper 下载页面【https://zookeeper.apache.org/releases.html】,下载 ZooKeeper 的编译程序 tar.gz 包到用户主目录中。
2、解压缩编译程序 tar 包到"/usr/local"目录中。
[centos@zookeeper1 ~]$ sudo tar zxvf apache-zookeeper-3.6.1-bin.tar.gz -C /usr/local
[centos@zookeeper1 ~]$ sudo mv /usr/local/apache-zookeeper-3.6.1-bin /usr/local/zookeeper-3.6.1
[centos@zookeeper1 ~]$ ll /usr/local
drwxr-xr-x. 6 root root 133 9月 9 11:22 zookeeper-3.6.1
3、创建 ZooKeeper 的数据存储目录。
[centos@zookeeper1 ~]$ sudo mkdir /data/zookeeper
4、创建 ZooKeeper 管理用户和组,并设置为程序安装目录、数据存储目录的拥有者。
[centos@zookeeper1 ~ ]$ sudo id zk
id: “zk”:无此用户
[centos@zookeeper1 ~ ]$ sudo groupadd zk
[centos@zookeeper1 ~ ]$ sudo useradd -g zk -s /bin/false zk
[centos@zookeeper1 ~ ]$ sudo chown -R zk:zk /usr/local/zookeeper-3.6.1
[centos@zookeeper1 ~ ]$ sudo chown -R zk:zk /data/zookeeper
5、设置 ZooKeeper 的配置文件参数。
从配置文件模板中拷贝生成配置文件:
[centos@zookeeper1 ~]$ sudo cp /usr/local/zookeeper-3.6.1/conf/zoo_sample.cfg /usr/local/zookeeper-3.6.1/conf/zoo.cfg
使用文本编辑器打开配置文件:
[centos@zookeeper1 ~]$ sudo gedit /usr/local/zookeeper-3.6.1/conf/zoo.cfg
修改或验证文件中的以下参数并保存:
# ZooKeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,单位毫秒,也就是每个 tickTime 时间就会发送一个心跳。
tickTime=2000
# ZooKeeper 接受客户端(这里所说的客户端不是用户连接 ZooKeeper 服务器的客户端,而是 ZooKeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10 个心跳的时间(也就是 tickTime)长度后 ZooKeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒。
initLimit=10
# ZooKeeper 标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 2*2000=4 秒。
syncLimit=5
# ZooKeeper 保存数据的目录,默认情况下,ZooKeeper 将写数据的日志文件也保存在这个目录里。
dataDir=/data/zookeeper
# ZooKeeper 服务监听端口,接受客户端的访问请求。
clientPort=2181
# ZooKeeper Http 服务监听端口,提供 Restful 风格的服务器管理接口。
admin.serverPort=2182
# ZooKeeper 接受的最大客户端连接数,默认不限制。
#maxClientCnxns=60
6、配置 ZooKeeper 服务开机自启动。
使用文本编辑器创建配置文件:
[centos@zookeeper1 ~]$ sudo gedit /usr/lib/systemd/system/zookeeper.service
编写文件内容并保存如下:
[Unit]
Description=ZooKeeper
After=syslog.target network.target
[Service]
Type=forking
User=zk
Group=zk
ExecStart=/usr/local/zookeeper-3.6.1/bin/zkServer.sh start /usr/local/zookeeper-3.6.1/conf/zoo.cfg
ExecStop=/usr/local/zookeeper-3.6.1/bin/zkServer.sh stop
ExecReload=/usr/local/zookeeper-3.6.1/bin/zkServer.sh restart
[Install]
WantedBy=multi-user.target
设置开机启动:
[centos@zookeeper1 ~]$ sudo systemctl daemon-reload
[centos@zookeeper1 ~]$ sudo systemctl enable zookeeper.service
7、启动 ZooKeeper 服务并查看服务状态。
[centos@zookeeper1 ~]$ sudo systemctl start zookeeper.service
[centos@zookeeper1 ~]$ sudo systemctl status zookeeper.service
8、设置防火墙端口(CentOS8默认安装firewall防火墙),允许"2181" 端口(ZooKeeper 默认端口)访问服务器。
[centos@zookeeper1 ~]$ sudo firewall-cmd --zone=public --add-port=2181/tcp --permanent
[centos@zookeeper1 ~]$ sudo firewall-cmd --reload
9、ZooKeeper 运维管理
1)启动 ZooKeeper 服务(任选一种方式)
[centos@zookeeper1 ~]$ sudo systemctl start zookeeper.service
或者
[centos@zookeeper1 ~]$ sudo -u zk /usr/local/zookeeper-3.6.1/bin/zkServer.sh start
2)停止 ZooKeeper 服务(任选一种方式)
[centos@zookeeper1 ~]$ sudo systemctl stop zookeeper.service
或者
[centos@zookeeper1 ~]$ sudo -u zk /usr/local/zookeeper-3.6.1/bin/zkServer.sh stop
3)重启 ZooKeeper 服务
[centos@zookeeper1 ~]$ sudo systemctl restart zookeeper.service
或者
[centos@zookeeper1 ~]$ sudo -u zk /usr/local/zookeeper-3.6.1/bin/zkServer.sh restart
4)查看 ZooKeeper 服务状态
[centos@zookeeper1 ~]$ sudo systemctl status zookeeper.service
或者
[centos@zookeeper1 ~]$ sudo netstat -ntap | grep 2181
tcp6 0 0 :::2181 :::* LISTEN 4879/java
5)开启 ZooKeeper 服务开机自启动
[centos@zookeeper1 ~]$ sudo systemctl enable zookeeper.service
6)禁用 ZooKeeper 服务开机自启动
[centos@zookeeper1 ~]$ sudo systemctl disable zookeeper.service
在多个实例并行的情况下,全部实例共享使用管理用户和组、但每个实例独立安装(包括独立的程序安装目录和数据存储目录)、独立端口、独立启动服务。
注意:其他 "ZooKeeper Server" 节点上全部需要按照以上步骤配置。
4.集群化配置
根据集群部署拓扑图,安装 "3.单点安装和配置" 章节的操作步骤完成所有 ZooKeeper Server 节点的安装和配置。
以"ZooKeeper Server 1"节点为例:
1、设置 ZooKeeper 的配置文件参数。
使用文本编辑器打开配置文件:
[centos@zookeeper1 ~]$ sudo gedit /usr/local/zookeeper-3.6.1/conf/zoo.cfg
在文件中追加以下参数并保存:
server.1=192.168.0.21:2888:3888
server.2=192.168.0.22:2888:3888
server.3=192.168.0.23:2888:3888
格式:server.[A]=[B]:[C]:[D]
说明:
[A]:节点序号(范围是 1 ~ 255),用于标记集群中的节点。这个序号记录在集群节点上 ZooKeeper 数据目录中的 myid 文件里,myid 文件需人工创建。
[B]:节点 IP 地址。
[C]:与集群 Leader 节点交换信息的端口号。
[D]:当集群 Leader 故障时,参与选举集群 Leader 节点的通信端口。
2、在 ZooKeeper 数据目录中创建 myid 文件并写入当前节点的序号。
使用文本编辑器创建 myid 文件:
[centos@zookeeper1 ~]$ sudo -u zk gedit /data/zookeeper/myid
在文件中写入当前节点的序号后保存(3 个节点分别是 "1"、"2"、"3"):
1
3、设置防火墙端口(CentOS8默认安装firewall防火墙),允许"2888"、"3888" 端口访问服务器。
[centos@zookeeper1 ~]$ sudo firewall-cmd --zone=public --add-port=2888/tcp --permanent
[centos@zookeeper1 ~]$ sudo firewall-cmd --zone=public --add-port=3888/tcp --permanent
[centos@zookeeper1 ~]$ sudo firewall-cmd --reload
注意:其他 "ZooKeeper Server" 节点上全部需要按照以上步骤配置。
4、所有 ZooKeeper Server 节点依次重新启动 ZooKeeper 服务。
[centos@zookeeper1 ~]$ sudo systemctl restart zookeeper.service
[centos@zookeeper2 ~]$ sudo systemctl restart zookeeper.service
[centos@zookeeper3 ~]$ sudo systemctl restart zookeeper.service
5、所有 ZooKeeper Server 节点依次查看 ZooKeeper 服务的状态。
[centos@zookeeper1 ~]$ sudo systemctl status zookeeper.service
[centos@zookeeper2 ~]$ sudo systemctl status zookeeper.service
[centos@zookeeper3 ~]$ sudo systemctl status zookeeper.service
6、所有 ZooKeeper Server 节点依次查看 ZooKeeper 的角色。
[centos@zookeeper1 ~]$ /usr/local/zookeeper-3.6.1/bin/zkServer.sh status
[centos@zookeeper2 ~]$ /usr/local/zookeeper-3.6.1/bin/zkServer.sh status
[centos@zookeeper3 ~]$ /usr/local/zookeeper-3.6.1/bin/zkServer.sh status
5.zkCli 客户端
1、登录 ZooKeeper Server。
1)登录本地 ZooKeeper Server:
[centos@zookeeper1 ~]$ sudo -u zk /usr/local/zookeeper-3.6.1/bin/zkCli.sh
[zk: localhost:2181(CONNECTED) 0]
2)登录远程 ZooKeeper Server:
[centos@zookeeper1 ~]$ sudo -u zk /usr/local/zookeeper-3.6.1/bin/zkCli.sh -server 192.168.0.21:2181
[zk: 192.168.0.21:2181(CONNECTING) 0]
2、zkCli 命令库。
ZooKeeper -server host:port -client-configuration properties-file cmd args
addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE
addauth scheme auth
close
config [-c] [-w] [-s]
connect host:port
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
delete [-v version] path
deleteall path [-b batch size]
delquota [-n|-b] path
get [-s] [-w] path
getAcl [-s] path
getAllChildrenNumber path
getEphemerals path
history
listquota path
ls [-s] [-w] [-R] path
printwatches on|off
quit
reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
redo cmdno
removewatches path [-c|-d|-a] [-l]
set [-s] [-v version] path data
setAcl [-s] [-v version] [-R] path acl
setquota -n|-b val path
stat [-w] path
sync path
version
3、查询指定 ZNode 的子节点列表。
格式:ls [-s] <path>
必选参数:
<path>:指定 ZNode 路径。可选参数:
[-s]:结果包含 ZNode 的状态信息。
1)查询子节点列表:
[zk: localhost:2181(CONNECTED) 0] ls /zookeeper
[config, quota]
2)查询子节点列表和状态信息:
[zk: localhost:2181(CONNECTED) 0] ls -s /zookeeper
[config, quota]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -2
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2
4、创建新的 ZNode (默认是不带顺序的持久类型节点)。
格式:create [-s] [-e] <path> <data> [acl]
必选参数:
<path>:指定 ZNode 路径。
<data>:指定 ZNode 数据。可选参数:
[acl]:指定 ZNode 的 ACL 权限,默认为 "world:anyone:cdwra"。
[-s]:指定 ZNode 的是一个顺序型节点。
[-e]:指定 ZNode 的是一个临时型节点。
1)创建不带顺序的持久型 ZNode:
[zk: localhost:2181(CONNECTED) 0] create /test "data"
Created /test
2)创建不带顺序的持久型 ZNode,并指定权限:
[zk: localhost:2181(CONNECTED) 0] create /test "data" world:anyone:cdwra
Created /test
3)创建带顺序的持久型 ZNode:
[zk: localhost:2181(CONNECTED) 0] create -s /test "data"
Created /test
4)创建不带顺序的临时型 ZNode:
[zk: localhost:2181(CONNECTED) 0] create -e /test "data"
Created /test
5)创建带顺序的临时型 ZNode:
[zk: localhost:2181(CONNECTED) 0] create -e -s /test "data"
Created /test
5、查看 ZNode 的内容。
格式:get [-s] <path>
必选参数:
<path>:指定 ZNode 路径。可选参数:
[-s]:结果包含 ZNode 的状态信息。
1)查看 ZNode 内容:
[zk: localhost:2181(CONNECTED) 0] get /test
data
2)查询子节点列表和状态信息:
[zk: localhost:2181(CONNECTED) 0] get -s /test
data
cZxid = 0x100000021
ctime = Wed Sep 09 15:06:34 CST 2020
mZxid = 0x100000021
mtime = Wed Sep 09 15:06:34 CST 2020
pZxid = 0x100000021
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
6、更新 ZNode 的内容。
格式:set <path> <newdata>
必选参数:
<path>:指定 ZNode 路径。
<data>:指定新的 ZNode 数据。
[zk: localhost:2181(CONNECTED) 0] set /test "newdata"
[zk: localhost:2181(CONNECTED) 29] get /test
newdata
7、查看 ZNode 的权限。
格式:getAcl <path>
必选参数:
<path>:指定 ZNode 路径。
<acl>:指定新的权限。
[zk: localhost:2181(CONNECTED) 0] getAcl /test
'world,'anyone
: cdrwa
8、添加认证信息到 ZooKeeper。
格式:addauth <scheme> <auth>
必选参数:
<scheme>:指定认证的方式,可选项包括: ip(IP 地址或 IP 地址段)、digest(用户名:口令)、world(默认值)。
<auth>:指定权限参数。
[zk: localhost:2181(CONNECTED) 0] addauth digest zk:123456
[zk: localhost:2181(CONNECTED) 0] addauth digest 192.168.0.0/24
9、设置 ZNode 的权限。
格式:set <path> <acl>
必选参数:
<path>:指定 ZNode 路径。
<acl>:指定新的权限。
[zk: localhost:2181(CONNECTED) 0] setAcl /test auth:zk:123456:cdrwa
[zk: localhost:2181(CONNECTED) 0] getAcl /test
'digest,'zk:N0YquoLgOZWu74hzsd3OJTZZUw0=
: cdrwa
[zk: localhost:2181(CONNECTED) 0] setAcl /test auth:192.168.0.0/24:cdrwa
[zk: localhost:2181(CONNECTED) 0] getAcl /test
'digest,'192.168.0.0/24:GPiECBE+zPr0tqF/5UxlmexODTg=
: cdrwa
10、删除没有子节点的 ZNode。
格式:delete <path>
必选参数:
<path>:指定 ZNode 路径。
[zk: localhost:2181(CONNECTED) 0] delete /test
11、递归删除 ZNode。
格式:rmr <path>
必选参数:
<path>:指定 ZNode 路径。
[zk: localhost:2181(CONNECTED) 0] deleteall /test
12、其他常用指令。
1)查看最近10条历史命令:
[zk: localhost:2181(CONNECTED) 0] history
2) 重新执行指定序号的命令:
[zk: localhost:2181(CONNECTED) 0] redo 1
3)查看版本:
[zk: localhost:2181(CONNECTED) 0] version
4)关闭当前连接,可用 connect 再次连接,不会退出客户端:
[zk: localhost:2181(CONNECTED) 0] close
5)重新连接本地服务器:
[zk: localhost:2181(CONNECTED) 0] connect
6)连接远程服务器:
[zk: localhost:2181(CONNECTED) 0] connect 192.168.0.22:2181
7)关闭连接并退出连接客户端:
[zk: localhost:2181(CONNECTED) 0] quit
6.Java 项目集成
客户端要连接 ZooKeeper 服务器可以通过引入 ZooKeeper 提供的 JavaAPI 创建 org.apache.zookeeper. ZooKeeper 的一个实例对象,然后调用这个类提供的接口来和服务器交互。
org.apache.zookeeper. ZooKeeper 类的主要方法包括:
方法 | 说明 |
---|---|
Stringcreate(String path, byte[] data, List<ACL> acl, CreateMode createMode) | 创建一个给定的目录节点 path, 并给它设置数据, CreateMode 标识有四种形式的目录节点,分别是 PERSISTENT:持久化目录节点,这个目录节点存储的数据不会丢失;PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名;EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session 超时,这种节点会被自动删除;EPHEMERAL_SEQUENTIAL:临时自动编号节点 |
Statexists(String path, boolean watch) | 判断某个 path 是否存在,并设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper 实例时指定的 watcher,exists 方法还有一个重载方法,可以指定特定的 watcher |
Statexists(String path, Watcher watcher) | 重载方法,这里给某个目录节点设置特定的 watcher,Watcher 在 ZooKeeper 是一个核心功能,Watcher 可以监控目录节点的数据变化以及子目录的变化,一旦这些状态发生变化,服务器就会通知所有设置在这个目录节点上的 Watcher,从而每个客户端都很快知道它所关注的目录节点的状态发生变化,而做出相应的反应 |
void delete(String path, int version) | 删除 path 对应的目录节点,version 为 -1 可以匹配任何版本,也就删除了这个目录节点所有数据 |
List<String> getChildren(String path, boolean watch) | 获取指定 path 下的所有子目录节点,同样 getChildren 方法也有一个重载方法可以设置特定的 watcher 监控子节点的状态 |
StatsetData(String path, byte[] data, int version) | 给 path 设置数据,可以指定这个数据的版本号,如果 version 为 -1 怎可以匹配任何版本 |
byte[] getData(String path, boolean watch, Stat stat) | 获取这个 path 对应的目录节点存储的数据,数据的版本等信息可以通过 stat 来指定,同时还可以设置是否监控这个目录节点数据的状态 |
void addAuthInfo(String scheme, byte[] auth) | 客户端将自己的授权信息提交给服务器,服务器将根据这个授权信息验证客户端的访问权限。 |
StatsetACL(String path, List<ACL> acl, int version) | 给某个目录节点重新设置访问权限,需要注意的是 Zookeeper 中的目录节点权限不具有传递性,父目录节点的权限不能传递给子目录节点。目录节点 ACL 由两部分组成:perms 和 id。 Perms 有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 几种 而 id 标识了访问目录节点的身份列表,默认情况下有以下两种: ANYONE_ID_UNSAFE = new Id("world", "anyone") 和 AUTH_IDS = new Id("auth", "") 分别表示任何人都可以访问和创建者拥有访问权限。 |
List<ACL> getACL(String path, Stat stat) | 获取某个目录节点的访问权限列表 |
1、从 Maven 库中引入 ZooKeeper 包。
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.1</version>
</dependency>
2、基本操作示例。
import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class ZooKeeperApp {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 创建一个与服务器的连接
ZooKeeper zk = new ZooKeeper("192.168.0.21:2181,192.168.0.22:2181,192.168.0.23:2181", 5000, new Watcher() {
// 监控所有被触发的事件
public void process(WatchedEvent event) {
System.out.println("已经触发了" + event.getType() + "事件!");
}
});
// 创建一个目录节点
zk.create("/testRootPath", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 创建一个子目录节点
zk.create("/testRootPath/testChildPathOne", "testChildDataOne".getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
System.out.println(new String(zk.getData("/testRootPath", false, null)));
// 取出子目录节点列表
System.out.println(zk.getChildren("/testRootPath", true));
// 修改子目录节点数据
zk.setData("/testRootPath/testChildPathOne", "modifyChildDataOne".getBytes(), -1);
System.out.println("目录节点状态:[" + zk.exists("/testRootPath", true) + "]");
// 创建另外一个子目录节点
zk.create("/testRootPath/testChildPathTwo", "testChildDataTwo".getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
System.out.println(new String(zk.getData("/testRootPath/testChildPathTwo", true, null)));
// 删除子目录节点
zk.delete("/testRootPath/testChildPathTwo", -1);
zk.delete("/testRootPath/testChildPathOne", -1);
// 删除父目录节点
zk.delete("/testRootPath", -1);
// 关闭连接
zk.close();
}
}
更多 Java 集成 ZooKeeper 的实例请阅读文章【https://developer.ibm.com/zh/articles/os-cn-zookeeper】。