一、ZooKeeper 安装

Zookeeper 支持多种安装方法

  • 二进制
  • 容器

https://hub.docker.com/_/zookeeper

1.1 ZooKeeper 单机部署

单机版的 ZooKeeper 安装

官方文档:

https://zookeeper.apache.org/doc/r3.6.2/zookeeperStarted.html#sc_InstallingsingleMode

1.1.1 配置 Java 环境

官方依赖介绍

https://zookeeper.apache.org/doc/r3.9.0/zookeeperAdmin.html#sc_systemReq

https://zookeeper.apache.org/doc/r3.8.0/zookeeperAdmin.html#sc_systemReq

https://zookeeper.apache.org/doc/r3.6.2/zookeeperAdmin.html#sc_requiredSoftware image

范例: ubuntu2404安装 JDK-21

[root@ubuntu2404 ~]#apt update && apt -y install openjdk-21-jdk
[root@ubuntu2404 ~]#java -version
openjdk version "21.0.7" 2025-04-15
OpenJDK Runtime Environment (build 21.0.7+6-Ubuntu-Oubuntu124.04)
OpenJDK 64-Bit Server VM (build 21.0.7+6-Ubuntu-Oubuntu124.04, mixed mode, sharing)

范例:ubuntu2204安装 JDK-11,17

[root@ubuntu2404 ~]#apt update && apt -y install openjdk-17-jdk
[root@ubuntu2404 ~]#apt update && apt -y install openjdk-11-jdk
[root@ubuntu2404 ~]#java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-Ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-Ubuntu122.04, mixed mode, sharing)

范例:ubuntu2004安装 JDK-11

[root@ubuntu2004 ~]#apt update && apt -y install openjdk-11-jdk
[root@ubuntu2004 ~]#java -version
openjdk version "11.0.9.1" 2020-11-04
OpenJDK Runtime Environment (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04)
OpenJDK 64-Bit Server VM (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)

范例: ubuntu1804安装 JDK-8

[root@ubuntu1804 ~]#apt update && apt -y install openjdk-8-jdk
[root@ubuntu1804 ~]#Java -version
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (build 1.8.0_282-8u282-b08-0ubuntu1~18.04-b08)
OpenJDK 64-Bit Server VM (build 25.282-b08, mixed mode)

1.1.2 部署 ZooKeeper

1.1.2.1 包安装

范例:系统内置包安装

[root@ubuntu2404 ~]#apt list zookeeper
Listing... Done
zookeeper/noble,noble 3.9.1-1build2 all
[root@ubuntu2404 ~]#apt update && apt -y install zookeeper

范例:系统内置包安装

[root@ubuntu2404 ~]#apt list zookeeper

正在列表... 完成
zookeeper/jammy 3.4.13-6ubuntu4 all

[root@ubuntu2404 ~]#apt -y install zookeeper
[root@ubuntu2404 ~]#grep -Ev "#|^$" /etc/zookeeper/conf/zoo.cfg
tickTime=2000 #服务器与服务器之间的单次心跳检测时间间隔,单位为毫秒
initLimit=10 #集群中leader 服务器与follower 服务器初始连接心跳次数,即多少个 2000 毫秒
syncLimit=5 #leader 与follower 之间检测发送和应答的心跳次数,如果该follower在时间段5*2000不能与leader进行通信,此 follower将不可用
dataDir=/var/lib/zookeeper #自定义的zookeeper保存数据的目录
clientPort=2181 #客户端连接 Zookeeper 服务器的端口,Zookeeper会监听这个端口,接受客户端的访问请求

[root@ubuntu2404 ~]#ls /usr/share/zookeeper/bin/

zkCleanup.sh zkCli.sh zkEnv.sh zkServer.sh

[root@ubuntu2404 ~]#/usr/share/zookeeper/bin/zkServer.sh start

Zookeeper JMX enabled by default
Using config: /etc/zookeeper/conf/zoo.cfg
Starting zookeeper ... STARTED

[root@ubuntu2404 ~]#/usr/share/zookeeper/bin/zkServer.sh status
Zookeeper JMX enabled by default
Using config: /etc/zookeeper/conf/zoo.cfg
Mode: standalone

1.1.2.2 二进制安装

https://zookeeper.apache.org/ image

历史版本下载

https://archive.apache.org/dist/zookeeper/ 版本: stable 和 current ,生产建议使用stable版本

范例: 安装单机 zookeeper

#安装JAVA
[root@ubuntu2404 ~]#apt update && apt -y install openjdk-21-jre
[root@ubuntu2004 ~]#apt update && apt -y install openjdk-11-jdk
[root@ubuntu2404 ~]#java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)

#官方下载
[root@ubuntu1804 ~]#wget -P /usr/local/src https://downloads.apache.org/zookeeper/stable/apache-zookeeper-3.6.3-bin.tar.gz

#国内镜像下载
[root@ubuntu2404 ~]#wget -P /usr/local/src https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.9.5/apache-zookeeper-3.9.5-bin.tar.gz
[root@ubuntu1804 ~]#wget -P /usr/local/src https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/stable/apache-zookeeper-3.6.3-bin.tar.gz

[root@ubuntu1804 ~]#tar xf /usr/local/src/apache-zookeeper-3.6.3-bin.tar.gz -C /usr/local/
[root@ubuntu1804 ~]#ln -s /usr/local/apache-zookeeper-3.6.3-bin /usr/local/zookeeper

#注意:不支持软链接到/usr/local/bin 目录,此方法会导致配置文件无法找到,无法启动
#支持修改PATH变量
[root@ubuntu1804 ~]#echo 'PATH=/usr/local/zookeeper/bin:$PATH' > /etc/profile.d/zookeeper.sh
[root@ubuntu1804 ~]#. /etc/profile.d/zookeeper.sh

[root@ubuntu1804 ~]#ll /usr/local/zookeeper/
total 48
drwxr-xr-x  6 root root  4096 Feb 15 19:19 ./
drwxr-xr-x 11 root root  4096 Feb 15 19:20 ../
drwxr-xr-x  2 wang wang  4096 Sep  4 20:43 bin/
drwxr-xr-x  2 wang wang  4096 Sep  4 20:43 conf/
drwxr-xr-x  5 wang wang  4096 Sep  4 20:44 docs/
drwxr-xr-x  2 root root  4096 Feb 15 19:19 lib/
-rw-r--r--  1 wang wang 11358 Sep  4 20:43 LICENSE.txt
-rw-r--r--  1 wang wang   432 Sep  4 20:43 NOTICE.txt
-rw-r--r--  1 wang wang  1963 Sep  4 20:43 README.md
-rw-r--r--  1 wang wang  3166 Sep  4 20:43 README_packaging.md

#2.3.1.3 启动 ZooKeeper
[root@ubuntu1804 ~]#ls /usr/local/zookeeper/bin/
README.txt   zkCli.cmd zkEnv.cmd zkServer.cmd           zkServer.sh           zkSnapShotToolkit.sh zkTxnLogToolkit.sh
zkCleanup.sh zkCli.sh   zkEnv.sh   zkServer-initialize.sh zkSnapShotToolkit.cmd zkTxnLogToolkit.cmd

[root@ubuntu1804 ~]#ls /usr/local/zookeeper/conf/
configuration.xsl log4j.properties   zoo_sample.cfg

#准备配置文件
[root@ubuntu1804 ~]#cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg

#默认配置可不做修改
[root@ubuntu1804 ~]#grep -v "#" /usr/local/zookeeper/conf/zoo.cfg
tickTime=2000  #"滴答时间",用于配置Zookeeper中最小的时间单元长度,单位毫秒,是其它时间配置的基础
initLimit=10   #初始化时间,包含启动和数据同步,其值是tickTime的倍数
syncLimit=5    #正常工作,心跳监测的时间间隔,其值是tickTime的倍数
dataDir=/tmp/zookeeper #配置Zookeeper服务存储数据快照的目录,可以自动创建,可以修改为 dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/logs  #指定日志路径,默认与 dataDir 一致,事务日志对性能影响非常大,强烈建议事务日志目录和数据目录分开,如果后续修改路径,需要先删除中dataDir中旧的事务日志,否则可能无法启动,此目录可以自动创建,
clientPort=2181 #配置当前Zookeeper服务对外暴露的端口,用户客户端和服务端建立连接会话

preAllocSize#为事务日志预先开辟磁盘空间。默认是64M,意味着每个事务日志初始大小64M。如果ZooKeeper产生快照频率较大,可以考虑减小这个参数,因为每次快照后都会切换到新的事务日志,即使前面的64M没有写满。
snapCount#该配置项指定ZooKeeper在将内存数据库保存为快照之前,需要先写多少次事务日志,即,每写几次事务日志就快照一次。默认值为100000。为了防止所有的ZooKeeper服务器节点同时生成快照(一般情况下,所有集群的实例的配置文件是完全相同的),当某节点的先写事务数量在(snapCount/2+1,snapCount)范围内时挑选一个随机值做为该节点拍快照的时机。

autopurge.snapRetainCount=3 #3.4.0中的新增功能:启用后,ZooKeeper 自动清除功能,会将只保留此最新3个快照和相应的事务日志,并分别保留在dataDir 和dataLogDir中,删除其余部分,默认值为3,最小值为3
autopurge.purgeInterval=24  #3.4.0及之后版本,ZK提供了自动清理日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认是 0,表示不开启自动清理功能

#通过prometheus监控的相关配置,需要stop再start,restart可能会失败
## Metrics Providers
#
# https://prometheus.io Metrics Exporter
#提供prometheus监控功能
metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
metricsProvider.httpHost=0.0.0.0
metricsProvider.httpPort=7000
metricsProvider.exportJvmInfo=true

1.1.3 启动 ZooKeeper

#查看选项
[root@ubuntu1804 ~]# zkServer.sh --help

[root@ubuntu2404 ~]# zkServer.sh version
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Apache ZooKeeper, version 3.9.3 2024-10-17 23:21 UTC

#前台启动观察启动过程
[root@ubuntu1804 ~]# zkServer.sh start-foreground

[root@ubuntu2404 ~]# curl 127.0.0.1:7000/metrics
global_sessions 0.0
# HELP connection_rejected connection_rejected
# TYPE connection_rejected counter
connection_rejected 0.0
# HELP read_commitproc_time_ms read_commitproc_time_ms
# TYPE read_commitproc_time_ms summary
read_commitproc_time_ms{quantile="0.5",} NaN
read_commitproc_time_ms{quantile="0.9",} NaN

#后台启动
[root@ubuntu1804 ~]# zkServer.sh start
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

#注意:如果配置service,zkServer.sh和systemctl不要混用,否则无法启动

1.1.4 验证 ZooKeeper

[root@ubuntu1804 ~]#zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: standalone

[root@ubuntu1804 ~]#ss -ntpl|grep 2181
LISTEN   0    50       *:2181       *:*    users:(("java",pid=1041,fd=70))

[root@ubuntu1804 ~]#pstree -p 1041
java(1041)─┬─{java}(1044)
           ├─{java}(1045)
           ├─{java}(1046)
           ├─{java}(1047)
           ├─{java}(1048)
           ├─{java}(1049)
           ├─{java}(1050)
           ├─{java}(1051)
           ├─{java}(1052)
           ├─{java}(1053)
           ├─{java}(1054)
           ├─{java}(1055)

1.1.5 service 文件

[root@ubuntu2404 ~]#cat > /lib/systemd/system/zookeeper.service <<EOF
[Unit]
Description=zookeeper.service
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/zookeeper/bin/zkServer.sh start
ExecStop=/usr/local/zookeeper/bin/zkServer.sh stop
ExecReload=/usr/local/zookeeper/bin/zkServer.sh restart

[Install]
WantedBy=multi-user.target
EOF

[root@ubuntu2404 ~]#systemctl daemon-reload
[root@ubuntu2404 ~]#systemctl enable --now zookeeper.service

[root@ubuntu2404 ~]#systemctl status zookeeper.service
● zookeeper.service
     Loaded: loaded (/lib/systemd/system/zookeeper.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2023-09-13 15:00:59 CST; 18s ago
    Process: 6413 ExecStart=/usr/local/zookeeper/bin/zkServer.sh start (code=exited, status=0/SUCCESS)
   Main PID: 6428 (java)
      Tasks: 36 (limit: 2196)
     Memory: 55.0M
        CPU: 2.033s
     CGroup: /system.slice/zookeeper.service
             └─6428 java -Dzookeeper.log.dir=/usr/local/zookeeper/bin/../logs -Dzookeeper.log.file=zookeeper--server-ubuntu2204.wang.org.log -XX:+HeapDumpOnOutOfMemoryErro>

9月 13 15:00:58 ubuntu2204.wang.org systemd[1]: Starting zookeeper.service...
9月 13 15:00:58 ubuntu2204.wang.org zkServer.sh[6413]: /usr/bin/java
9月 13 15:00:58 ubuntu2204.wang.org zkServer.sh[6413]: ZooKeeper JMX enabled by default
9月 13 15:00:58 ubuntu2204.wang.org zkServer.sh[6413]: Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
9月 13 15:00:59 ubuntu2204.wang.org zkServer.sh[6413]: Starting zookeeper ... STARTED
9月 13 15:00:59 ubuntu2204.wang.org systemd[1]: Started zookeeper.service.

1.1.6 一键安装 ZooKeeper 脚本

#!/bin/bash

ZK_VERSION=3.8.0
#ZK_VERSION=3.6.3
#ZK_VERSION=3.7.1

ZK_URL=https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-${ZK_VERSION}/apache-zookeeper-${ZK_VERSION}-bin.tar.gz
#ZK_URL="https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/stable/apache-zookeeper-${ZK_VERSION}-bin.tar.gz"
#ZK_URL="https://downloads.apache.org/zookeeper/stable/apache-zookeeper-${ZK_VERSION}-bin.tar.gz"

INSTALL_DIR=/usr/local/zookeeper
HOST=`hostname -I|awk '{print $1}'`

. /etc/os-release

color () {
    RES_COL=60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    SETCOLOR_SUCCESS="echo -en \\033[1;32m"
    SETCOLOR_FAILURE="echo -en \\033[1;31m"
    SETCOLOR_WARNING="echo -en \\033[1;33m"
    SETCOLOR_NORMAL="echo -en \E[0m"
    echo -n "$1" && $MOVE_TO_COL
    echo -n "["
    if [ $2 = "success" -o $2 = "0" ] ;then
        ${SETCOLOR_SUCCESS}
        echo -n $" OK "
    elif [ $2 = "failure" -o $2 = "1" ] ;then
        ${SETCOLOR_FAILURE}
        echo -n $"FAILED"
    else
        ${SETCOLOR_WARNING}
        echo -n $"WARNING"
    fi
    ${SETCOLOR_NORMAL}
    echo -n "]"
    echo
}

install_jdk() {
    if [ $ID = 'centos' -o  $ID = 'rocky' ];then
       yum -y install java-1.8.0-openjdk-devel || { color "安装JDK失败!" 1; exit 1; }
    else
       apt update
       apt install openjdk-11-jdk -y || { color "安装JDK失败!" 1; exit 1; }
        #apt install openjdk-8-jdk -y || { color "安装JDK失败!" 1; exit 1; }
    fi
    java -version
}

install_zookeeper() {
    wget -P /usr/local/src/ --no-check-certificate $ZK_URL || { color  "下载失败!" 1 ;exit ; }
    tar xf /usr/local/src/${ZK_URL##*/} -C /usr/local
    ln -s /usr/local/apache-zookeeper-*-bin/ ${INSTALL_DIR}
    echo "PATH=${INSTALL_DIR}/bin:$PATH" > /etc/profile.d/zookeeper.sh
    . /etc/profile.d/zookeeper.sh
    mkdir -p ${INSTALL_DIR}/data
    cat > ${INSTALL_DIR}/conf/zoo.cfg <<EOF
tickTime=2000
initLimit=10
syncLimit=5
dataDir=${INSTALL_DIR}/data
datalogDir=${INSTALL_DIR}/logs
clientPort=2181
maxClientCnxns=128
autopurge.snapRetainCount=3
autopurge.purgeInterval=24
EOF
    cat > /lib/systemd/system/zookeeper.service <<EOF
[Unit]
Description=zookeeper.service
After=network.target

[Service]
Type=forking
#Environment=${INSTALL_DIR}
ExecStart=${INSTALL_DIR}/bin/zkServer.sh start
ExecStop=${INSTALL_DIR}/bin/zkServer.sh stop
ExecReload=${INSTALL_DIR}/bin/zkServer.sh restart

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable --now zookeeper.service
    systemctl is-active zookeeper.service
    if [ $? -eq 0 ] ;then
        color "zookeeper 安装成功!" 0
    else
        color "zookeeper 安装失败!" 1
        exit 1
    fi
}

install_jdk
install_zookeeper

1.2 ZooKeeper 集群部署

1.2.1 ZooKeeper 集群介绍

ZooKeeper集群用于解决单点和单机性能及数据高可用等问题。

1.2.1.1 集群结构

image

image

Zookeeper集群基于Master/Slave的模型

处于主要地位负责处理写操作)的主机称为Leader节点,处于次要地位主要负责处理读操作的主机称为 follower 节点

Zookeeper的读写机制

  • 写操作:在Zookeeper中,写操作(如创建、删除、更新节点等)通常由Leader节点处理。当客户端发送写请求时,Leader会先将其写入本地日志,并尝试将其同步到集群中的其他Follower节点。一旦大多数在总数过半的节点成功应用了这个写操作,Leader就会认为这次写操作是成功的,并返回结果给客户端
  • 读操作:读操作可以由Leader或Follower节点处理。为了提高读取性能,Zookeeper通常会采用异步复制的方式,即Follower节点会异步地从Leader节点复制最新的数据。这样,即使Follower节点的数据不是最新的,它仍然可以处理读请求,并在后续从Leader节点获取更新的数据。生产中读取的方式在提高性能和容错性方面具有显著优势,同时也在一定程度上牺牲了数据的一致性。然而,对于大多数应用场景来说,这种折衷是合理的。

对于n台server,每个server都知道彼此的存在。只要有>n/2台server节点可用,整个zookeeper系统保持可用。因此zookeeper集群通常由奇数台Server节点组成

官方链接: 下图表示读的比例越高,性能越好

910 clients

image

1.2.1.2 集群角色

image

序号 角色 职责描述
1 领导者(Leader) 负责处理写入请求的,事务请求的唯一调度和处理者,负责进行投票发起和决议,更新系统状态
2 跟随者(Follower) 接收客户请求并向客户端返回结果,在选Leader过程中参与投票
3 观察者(Observer) 转交客户端写请求给leader节点,和同步leader状态和Follower唯一区别就是不参与Leader投票,也不参与写操作的"过半写成功"策略
4 学习者(Learner) 和leader进行状态同步的节点统称Learner,包括:Follower和Observer
5 客户端(client) 请求发起方

1.2.1.3 选举过程

节点角色状态:

  • LOOKING:寻找 Leader 状态,处于该状态需要进入选举流程
  • LEADING:领导者状态,处于该状态的节点说明是角色已经是Leader
  • FOLLOWING:跟随者状态,表示 Leader已经选举出来,当前节点角色是follower
  • OBSERVER:观察者状态,表明当前节点角色是 observer

选举 ID:

  • ZXID(zookeeper transaction id):每个改变 Zookeeper状态的操作都会自动生成一个对应的zxid。ZXID最大的节点优先选为Master/Lead
  • myid:服务器的唯一标识(SID),通过配置 myid 文件指定,集群中唯一,当ZXID一样时,myid大的节点优先选为Leader

ZooKeeper 集群选举过程:

当集群中的 zookeeper 节点启动以后,会根据配置文件中指定的 zookeeper节点地址进行leader 选择操作,过程如下:

  • 每个zookeeper 都会发出投票,由于是第一次选举leader,因此每个节点都会把自己当做leader 角色进行选举,每个zookeeper 的投票中都会包含自己的myid和zxid,此时zookeeper 1 的投票为myid 为 1,初始zxid有一个初始值0x0,后期会随着数据更新而自动变化,zookeeper 2 的投票为myid 为2,初始zxid 为初始生成的值。
  • 每个节点接受并检查对方的投票信息,比如投票时间、是否状态为LOOKING状态的投票。
  • 对比投票,优先检查zxid,如果zxid 不一样则 zxid 大的为leader,如果zxid相同则继续对比myid,myid 大的一方为 leader,成为 Leader 的必要条件: Leader 要具有最高的zxid;当集群的规模是 n 时,集群中大多数的机器(至少n/2+1 )得到响应并从follower 中选出的 Leader。

心跳机制:Leader 与 Follower 利用 PING 来感知对方的是否存活,当 Leader无法响应PING 时,将重新发起 Leader 选举。

当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB(Zookeeper Atomic Broadcast) 协议就会进入恢复模式并选举产生新的Leader服务器。这个过程大致如下:

Leader Election(选举阶段):节点在一开始都处于选举阶段,只要有一个节点得到超半数节点的票数,它就可以当选准 leader。

Discovery(发现阶段):在这个阶段,followers 跟准 leader 进行通信,同步 followers 最近接收的事务提议。

Synchronization(同步阶段):同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。同步完成之后 准leader 才会成为真正的 leader。

Broadcast(广播阶段) :到了这个阶段,Zookeeper 集群才能正式对外提供事务服务,并且 leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步

在分布式系统中,有多种协议被设计来解决一致性问题,Paxos、Raft、ZAB 等分布式算法经常会被称作是“强一致性”的分布式共识协议

强一致指的是尽管系统内部节点可以存在不一致的状态,但从系统外部看来,不一致的情况并不会被观察到,所以整体上看系统是强一致性的,对于CAP模型,实现的CP。

ZAB(ZooKeeper Atomic Broadcast 原子广播):Zab协议是由Apache ZooKeeper项目提出的一种原子广播协议,是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。

它主要用于构建一个高可用、高性能的分布式协调服务。Zab协议保证了分布式过程中的消息顺序一致性和崩溃恢复能力。它主要用在主-备模式的系统中,例如Kafka在2.8.0版本之前依赖ZooKeeper作为其元数据的存储,并使用Zab协议来保证数据的一致性。

Paxos:Paxos(帕克索斯)是Leslie Lamport( 在2013 年获得计算界的最高奖图灵奖) 早在1990年提出的分布式一致性算法之一,它能解决分布式环境中的一致性问题。Paxos算法可以保证在非同步和非可靠的分布式系统中,节点间可以达成一致的决定。不过,Paxos的描述和实现被公认为相对复杂,这也是Raft等其他一致性算法出现的原因。

使用Paxos或其变体协议的有如下应用

Google Chubby(Google的一个锁服务),Apache Cassandra(度可扩展的分布式数据库),Microsoft Azure Cosmos DB(Microsoft Azure提供的一个全球分布式、多模型的数据库服务),Riak(Microsoft Azure提供的一个全球分布式、多模型的数据库服务)

Raft:Raft协议由Diego Ongaro和John Ousterhout在2013年提出的。他们在斯坦福大学就读博士期间设计并研究了Raft。他们的主要目标是创建一个与Paxos功能相同,但更容易理解和实现的一致性算法。Raft 是一个为分布式系统提供一致性的算法。与Paxos相比,Raft的主要目标是提供一种更加易于理解和实现的一致性算法。Raft通过选举算法确保了分布式系统中的领导者唯一性。所有的写操作都通过领导者完成,这样就可以确保所有复制节点上的数据一致性。一些知名的分布式系统,如:kafka,etcd,nacos和Consul,都采用了Raft算法。

Gossip 谣言协议

与上面的协义相对的,还有另一类被冠以“最终一致性”的分布式共识协议,这表明系统中不一致的状态有可能会在一定时间内被外部直接观察到。一种典型且极为常见的最终一致的分布式系统就是DNS 系统,在各节点缓存的 TTL 到期之前,都有可能与真实的域名翻译结果存在不一致。有一种具有代表性的“最终一致性”的分布式共识协议:Gossip 协议。

Gossip 最早由施乐公司Xerox(计算机许多关键技术的鼻祖,图形界面的发明者、以太网的发明者、激光打印机的发明者、MVC 架构的提出者、RPC 的提出者、BMP 格式的提出者……) Palo Alto 研究中心在论文《Epidemic Algorithms for Replicated Database Maintenance》中提出的一种用于分布式数据库在多节点间复制同步数据的算法。从论文题目中可以看出,最初它是被称作“流行病算法”(EpidemicAlgorithm)的,今天 Gossip 这个名字已经用得更为普遍了,除此以外,它还有“流言算法”、“八卦算法”、“瘟疫算法”等别名,这些名字都是很形象化的描述,反应了 Gossip 的特点:要同步的信息如同流言一般传播、病毒一般扩散。

相比 Paxos、Raft 等算法,Gossip 的过程十分简单,它可以看作是以下两个步骤的简单循环:

如果有某一项信息需要在整个网络中所有节点中传播,那从信息源开始,选择一个固定的传播周期(譬如 1 秒),随机选择它相连接的k 个节点(称为 Fan-Out)来传播消息。

每一个节点收到消息后,如果这个消息是它之前没有收到过的,将在下一个周期内,选择除了发送消息给它的那个节点外的其他相邻 k个节点发送相同的消息,直到最终网络中所有节点都收到了消息,尽管这个过程需要一定时间,但是理论上最终网络的所有节点都会拥有相同的消息。

image

上图是 Gossip 传播过程的示意图,根据示意图和 Gossip 的过程描述,我们很容易发现 Gossip 对网络节点的连通性和稳定性几乎没有任何要求,它一开始就将网络某些节点只能与一部分节点[部分连通Partially Connected Network而不是以全连通网络Fully ConnectedNetwork)作为前提;能够容忍网络上节点的随意地增加或者减少,随意地宕机或者重启,新增加或者重启的节点的状态最终会与其他节点同步达成一致。Gossip 把网络上所有节点都视为平等而普通的一员,没有任何中心化节点或者主节点的概念,这些特点使得 Gossip 具有极强的鲁棒性Robust,而且非常适合在公众互联网中应用。

同时我们也很容易找到 Gossip 的缺点,消息最终是通过多个轮次的散播而到达全网的,因此它必然会存在全网各节点状态不一致的情况,而且由于是随机选取发送消息的节点,所以尽管可以在整体上测算出统计学意义上的传播速率,但对于个体消息来说,无法准确地预计到需要多长时间才能达成全网一致。另外一个缺点是消息的冗余,同样是由于随机选取发送消息的节点,也就不可避免的存在消息重复发送给同一节点的情况,增加了网络的传输的压力,也给消息节点带来额外的处理负载。

1.2.1.4 ZooKeeper 集群特性

整个集群中只要有超过集群数量一半的 zookeeper工作是正常的,那么整个集群对外就是可用的

假如有 2 台服务器做了一个 Zookeeper 集群,只要有任何一台故障或宕机,那么这个 ZooKeeper集群就不可用了,因为剩下的一台没有超过集群一半的数量,但是假如有三台zookeeper 组成一个集群, 那么损坏一台就还剩两台,大于 3台的一半,所以损坏一台还是可以正常运行的,但是再损坏一台就只剩一台集群就不可用了。那么要是 4 台组成一个zookeeper集群,损坏一台集群肯定是正常的,那么损坏两台就还剩两台,那么2台不大于集群数量的一半,所以 3 台的 zookeeper 集群和 4 台的 zookeeper集群损坏两台的结果都是集群不可用,以此类推 5 台和 6 台以及 7 台和 8台都是同理

1.2.1.5 Zookeeper 事务日志和快照

ZooKeeper集群中的每个服务器节点每次接收到写操作请求时,都会先将这次请求发送给leader

leader将这次写操作转换为带有状态的事务,然后leader会对这次写操作广播出去以便进行协调。

当协调通过(大多数节点允许这次写)后,leader通知所有的服务器节点,让它们将这次写操作应用到内存数据库中,并将其记录到事务日志中。

当事务日志记录的次数达到一定数量后(默认10W次),就会将内存数据库序列化一次,使其持久化保存到磁盘上,序列化后的文件称为"快照文件"。

每次拍快照都会生成新的事务日志。

1.2.2 ZooKeeper 集群部署

官方文档:

https://zookeeper.apache.org/doc/r3.6.2/zookeeperAdmin.html#sc_zkMulitServerSetup

1.2.2.1 环境准备

#三台ubuntu18.04,20.04,22.04
zookeeper-node1.wang.org 10.0.0.101
zookeeper-node2.wang.org 10.0.0.102
zookeeper-node3.wang.org 10.0.0.103

#在三个节点都安装JDK8或JDK11,JDK21
[root@zookeeper-node1 ~]#apt update && apt -y install openjdk-21-jdk
[root@zookeeper-node1 ~]#apt update && apt -y install openjdk-11-jdk
[root@zookeeper-node1 ~]#apt update && apt -y install openjdk-8-jdk
[root@zookeeper-node2 ~]#apt update && apt -y install openjdk-8-jdk
[root@zookeeper-node3 ~]#apt update && apt -y install openjdk-8-jdk

1.2.2.2 在所有节点下载并解压缩 ZooKeeper 包文件

[root@zookeeper-node1 ~]#wget -P /usr/local/src https://downloads.apache.org/zookeeper/stable/apachezookeeper-3.6.3-bin.tar.gz
[root@zookeeper-node1 ~]#tar xf /usr/local/src/apache-zookeeper-3.6.3-bin.tar.gz -C /usr/local/
[root@zookeeper-node1 ~]#ln -s /usr/local/apache-zookeeper-3.6.3-bin /usr/local/zookeeper
[root@zookeeper-node1 ~]#echo 'PATH=/usr/local/zookeeper/bin:$PATH' > /etc/profile.d/zookeeper.sh
[root@zookeeper-node1 ~]#. /etc/profile.d/zookeeper.sh

1.2.2.3 准备配置文件

三个节点都要创建数据目录

#三个节点都要创建数据目录
[root@zookeeper-node1 ~]#mkdir /usr/local/zookeeper/data 
#基于模板配置文件生成配置文件
[root@zookeeper-node1 ~]#cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
#修改配置文件
[root@zookeeper-node1 ~]#vim /usr/local/zookeeper/conf/zoo.cfg
#配置文件内容
[root@zookeeper-node1 ~]#grep -v "\^\#" /usr/local/zookeeper/conf/zoo.cfg 
tickTime=2000  #服务器与服务器之间的单次心跳检测时间间隔单位为毫秒
initLimit=10  #集群中leader 服务器与follower服务器初始连接心跳次数即多少个 2000 毫秒
syncLimit=5  #leader 与follower之间连接完成之后后期检测发送和应答的心跳次数如果该follower在设置的时间内(5*2000)不能与
leader 进行通信那么此 follower将被视为不可用
dataDir=/usr/local/zookeeper/data #自定义的zookeeper保存数据的目录
dataLogDir=/usr/local/zookeeper/logs  #指定日志路径默认与 dataDir 一致,事务日志对性能影响非常大强烈建议事务日志目录和
数据目录分开如果后续修改路径需要先删除中dataDir中旧的事务日志否则可能无法启动
clientPort=2181 #客户端连接 Zookeeper 服务器的端口Zookeeper会监听这个端口接受客户端的访问请求
maxClientCnxns=128 #单个客户端IP 可以和zookeeper保持的连接数
autopurge.snapRetainCount=3 #3.4.0中的新增功能启用后ZooKeeper 自动清除功能,会将只保留此最新3个快照和相应的事务日志,并分
别保留在dataDir 和dataLogDir中删除其余部分默认值为3,最小值为3
autopurge.purgeInterval=24  #3.4.0及之后版本ZK提供了自动清理日志和快照文件的功能这个参数指定了清理频率单位是小时需要
配置一个1或更大的整数默认是 0表示不开启自动清理功能
#格式: server.MyID服务器唯一编号=服务器IP:Leader和Follower的数据同步端口(只有leader才会打开):Leader和Follower选举端口(L和
F都有)
server.1=10.0.0.101:2888:3888
server.2=10.0.0.102:2888:3888
server.3=10.0.0.103:2888:3888
#如果添加节点,只需要在所有节点上添加新节点的上面形式的配置行,在新节点创建myid文件,并重启所有节点服务即可
[root@zookeeper-node1 ~]#scp /usr/local/zookeeper/conf/zoo.cfg 10.0.0.102:/usr/local/zookeeper/conf/
[root@zookeeper-node1 ~]#scp /usr/local/zookeeper/conf/zoo.cfg 10.0.0.103:/usr/local/zookeeper/conf/

1.2.2.4 在各个节点生成ID文件

注意: 各个myid文件的内容要和zoo.cfg文件相匹配

[root@zookeeper-node1 ~]#mkdir /usr/local/zookeeper/data; echo 1 > /usr/local/zookeeper/data/myid
[root@zookeeper-node2 ~]#mkdir /usr/local/zookeeper/data; echo 2 > /usr/local/zookeeper/data/myid
[root@zookeeper-node3 ~]#mkdir /usr/local/zookeeper/data; echo 3 > /usr/local/zookeeper/data/myid

1.2.2.5 各服务器启动 Zookeeper

注意:在所有三个节点快速启动服务,否则会造成集群失败

[root@zookeeper-node1 ~]#zkServer.sh start
[root@zookeeper-node2 ~]#zkServer.sh start
[root@zookeeper-node3 ~]#zkServer.sh start

#注意:如果无法启动查看日志
[root@zookeeper-node1 ~]#cat /usr/local/zookeeper/logs/zookeeper-root-server-zookeeper-node1.wang.org.out

1.2.2.6 查看集群状态

#follower会监听3888/tcp端口
[root@zookeeper-node1 ~]#zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
[root@zookeeper-node1 ~]#ss -ntl |grep 888
LISTEN  0        50         [::ffff:10.0.0.101]:3888                 *:*   
#只有leader监听2888/tcp端口
[root@zookeeper-node2 ~]#zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: leader
[root@zookeeper-node2 ~]#ss -ntl|grep 888
LISTEN  0        50         [::ffff:10.0.0.102]:3888                 *:*      
LISTEN  0        50         [::ffff:10.0.0.102]:2888                 *:*   
[root@zookeeper-node3 ~]#zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
[root@zookeeper-node3 ~]#ss -ntl|grep 888
LISTEN  0        50         [::ffff:10.0.0.103:3888                 *:*

1.3 容器化部署

范例: 单实例

docker run --name some-zookeeper -p 2181:2181 --restart always -d zookeeper

范例: 集群部署

#基于docker-compose部署zookeeper集群
version: '3.1'
services:
  zoo1:
    image: zookeeper
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo2:
    image: zookeeper
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo3:
    image: zookeeper
    restart: always
    hostname: zoo3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2ports:

二、ZooKeeper 客户端访问

2.1 命令行客户端访问 ZooKeeper

可连接至zookeeper 集群中的任意一台zookeeper 节点进行以下操作,zkcli.sh 默认连接本机

#可连接至zookeeper 集群中的任意一台zookeeper 节点进行以下操作,zkCli.sh 默认连接本机
[root@zookeeper-node1 ~]#zkCli.sh -server 10.0.0.103:2181
[zk: 10.0.0.103:2181(CONNECTED) 0] ls /
[zookeeper]

[zk: 10.0.0.103:2181(CONNECTED) 1]    #输入TAB键可以列出所有支持命令
addWatch       addauth   close         config connect       create               
delete         deleteall delquota       get    getAcl         getAllChildrenNumber   
getEphemerals   history   listquota      ls     printwatches   quit                 
reconfig       redo      removewatches  set    setAcl         setquota               
stat           sync      version 

[zk: 10.0.0.103:2181(CONNECTED) 1] version
ZooKeeper CLI version: 3.6.2--803c7f1a12f85978cb049af5e4ef23bd8b688715, built on 09/04/2020 12:44 GMT

#默认创建持久节点,即退出不丢失,create -e 可以创建临时节点(退出就丢失)
#持久节点才支持创建子节点,临时节点不支持,: create /app1/subapp1 "subdata" 不能递归创建
[zk: 10.0.0.103:2181(CONNECTED) 2] create /app1 "hello,zookeeper"
Created /app1

[zk: 10.0.0.103:2181(CONNECTED) 3] ls /
[app1, zookeeper]

#get -s /app1可以查看更详细的信息
[zk: 10.0.0.103:2181(CONNECTED) 4] get /app1
hello,zookeeper

#修改已有节点的值
[zk: 10.0.0.103:2181(CONNECTED) 5] set /app1 "hello,linux"

[zk: 10.0.0.103:2181(CONNECTED) 6] get /app1 
hello,linux

#删除不包含子节点的节点(相当于rmdir),如果想删除所有节点内的数据,使用deleteall /path(相当于rm -rf)
[zk: 10.0.0.103:2181(CONNECTED) 7] delete /app1

[zk: 10.0.0.103:2181(CONNECTED) 8] ls /
[zookeeper]

#查看已知节点元数据
[zk: 10.0.0.103:2181(CONNECTED) 9] stat /zookeeper
zxid = 0x0 #节点创建时的zxid
ctime = Thu Jan 01 08:00:00 CST 1970    #节点创建时间
mzxid = 0x0 #节点最近一次更新时的zxid
mtime = Thu Jan 01 08:00:00 CST 1970    #节点最近一次更新的时间
pzxid = 0x0                             #父节点创建时的zxid
cversion = -1                           #子节点数据更新次数
dataversion = 0                         #本节点数据更新次数
aclversion = 0                          #节点ACL(授权信息)的更新次数
ephemeralOwner = 0x0                    #持久节点值为0临时节点值为sessionid
dataLength = 0                          #节点数据长度
numChildren = 1                         #子节点个数

[zk: localhost:2181(CONNECTED) 10] get /zookeeper/config
server.1=10.0.0.201:2888:3888:participant
server.2=10.0.0.202:2888:3888:participant
server.3=10.0.0.203:2888:3888:participant
version=0

[zk: 10.0.0.103:2181(CONNECTED) 10] quit #退出

2.2 nc 访问 ZooKeeper 管理

ZooKeeper支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper服务的当前状态及相关信息。

用户在客户端可以通过 netcat 或telnet向zookeeper发送下面命令

常见命令列表

conf #输出相关服务配置的详细信息
cons #列出所有连接到服务器的客户端的完全的连接/会话的详细信息
envi #输出关于服务环境的详细信息
dump #列出未经处理的会话和临时节点
stat #查看哪个节点被选择作为Follower或者Leader
ruok #测试是否启动了该Server,若回复imok表示已经启动
mntr #输出一些运行时信息
reqs #列出未经处理的请求
wchs #列出服务器watch的简要信息
wchc #通过session列出服务器watch的详细信息
wchp #通过路径列出服务器watch的详细信息
srvr #输出服务的所有信息
srst #重置服务器统计信息
kill #关掉Server,当前版本无法关闭
isro #查看该服务的节点权限信息

命令的安全限制

#默认情况下,这些4字命令有可能会被拒绝,提示如下报错
xxxx is not executed because it is not in the whitelist.

#解决办法:在 zoo.cfg文件中添加如下配置,如果是集群需要在所有节点上添加下面配置
# vim conf/zoo.cfg
4lw.commands.whitelist=*

#在服务状态查看命令中有很多存在隐患的命令,为了避免生产中的安全隐患,要对这些"危险"命令进行一些安全限制,只需要编辑服务的zoo.cfg文件即可
# vim conf/zoo.cfg
4lw.commands.whitelist=conf,stat,ruok,isro

范例:

#ubuntu18.04安装netcat
apt update && apt -y install netcat-traditional 或者 netcat-openbsd

#查看节点服务状态
echo stat | nc 127.0.0.1 2181
#如果不显式写入白名单默认提示stat is not executed because it is not in the whitelist.

#查看节点服务配置
echo conf | nc 127.0.0.1 2181

#查看节点服务环境
echo envi | nc 127.0.0.1 2181

#查看节点服务会话
echo cons | nc 127.0.0.1 2181
echo dump | nc 127.0.0.1 2181

#也支持 telnet,但不能用 | telnet 形式
[root@ubuntu1804 ~]#telnet 127.0.0.1 2181
Trying 10.0.0.8...
Connected to 10.0.0.8.
Escape character is '^]'.
cons
 /10.0.0.100:52154[0](queued=0,recved=1,sent=0)
 /127.0.0.1:59566[1]
(queued=0,recved=8,sent=8,sid=0x100004b74080001,lop=PING,est=1635560454029,to=30000,lcxid=0x0,lzxid=0x9,lresp=5205692,llat=0,minlat=0,avglat=0,maxlat=2)
Connection closed by foreign host.

2.3 图形化客户端 ZooInspector

github链接

https://github.com/zzhang5/zooinspector

https://gitee.com/lbtooth/zooinspector.git

2.3.1 Linux 客户端

2.3.1.1 编译 zooinspector

注意:此软件因年代久远不再更新,只支持 JAVA-8,且不支持Ubuntu20.04,但支持Ubuntu22.04和Rocky8

# ZooInspector 编译与运行ZooKeeper 可视化工具
# https://github.com/zzhang5/zooinspector

# 下载源码
git clone https://github.com/zzhang5/zooinspector.git
cd zooinspector/

# 编译打包跳过测试避免构建失败
mvn clean package -Dmaven.test.skip=true

# 赋予执行权限并启动
chmod +x target/zooinspector-pkg/bin/zooinspector.sh
target/zooinspector-pkg/bin/zooinspector.sh

image

范例: Ubuntu24.04 编译 zooinspector

#注意只支持JAVA-8不支持JAVA-11以上版本
[root@ubuntu2404 ~]#apt update && apt -y install openjdk-8-jdk
[root@ubuntu2404 ~]#apt update && apt -y install maven

[root@ubuntu2404 ~]#mvn -v
Apache Maven 3.8.7
Maven home: /usr/share/maven
Java version: 1.8.0_442, vendor: Private Build, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-48-generic", arch: "amd64", family: "unix"

[root@ubuntu2404 ~]#vim /etc/maven/settings.xml 
 <mirrors>
   <!--阿里云镜像-->
   <mirror>
       <id>nexus-aliyun</id>
       <mirrorOf>*</mirrorOf>
       <name>Nexus aliyun</name>
       <url>http://maven.aliyun.com/nexus/content/groups/public</url>
   </mirror>                         
 </mirrors>

[root@ubuntu2404 ~]#git clone https://gitee.com/lbtooth/zooinspector.git
[root@ubuntu2404 ~]#git clone https://github.com/zzhang5/zooinspector.git
[root@ubuntu2404 ~]#git clone https://mirror.ghproxy.com/https://github.com/zzhang5/zooinspector.git

[root@ubuntu2404 ~]#cd zooinspector/
[root@ubuntu2404 zooinspector]#ls
pom.xml README.md src target

[root@ubuntu2404 zooinspector]#mvn clean package -Dmaven.test.skip=true
......
[WARNING] Entry: zooinspector-1.0-SNAPSHOT/repo/org/apache/zookeeper/zooinspector/1.0-SNAPSHOT/zooinspector-1.0-SNAPSHOT.jar longer than 100 characters.
[WARNING] Resulting tar file can only be processed successfully by GNU compatible tar commands
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  44.276 s
[INFO] Finished at: 2025-03-07T16:09:33+08:00
[INFO] ------------------------------------------------------------------------

[root@ubuntu2404 zooinspector]#chmod +x zooinspector-pkg/bin/zooinspector.sh
[root@ubuntu2404 zooinspector]#./target/zooinspector-pkg/bin/zooinspector.sh

#将此文件传到windows上解开运行zooinspector.bat
[root@ubuntu2404 zooinspector]#sz target/zooinspector-1.0-SNAPSHOT-pkg.tar

范例: Ubuntu22.04 编译 zooinspector

#注意只支持JAVA-8不支持JAVA-11以上版本
[root@ubuntu2404 ~]#apt update && apt -y install openjdk-8-jdk -y
[root@ubuntu2404 ~]#apt update && apt -y install maven

[root@ubuntu2404 ~]#mvn -v
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 1.8.0_422, vendor: Private Build, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-52-generic", arch: "amd64", family: "unix"

[root@ubuntu2404 ~]#vim /etc/maven/settings.xml 
 <mirrors>
   <!--阿里云镜像-->
   <mirror>
       <id>nexus-aliyun</id>
       <mirrorOf>*</mirrorOf>
       <name>Nexus aliyun</name>
       <url>http://maven.aliyun.com/nexus/content/groups/public</url>
   </mirror>                         
 </mirrors>

[root@ubuntu2404 ~]#git clone https://github.com/zzhang5/zooinspector.git
[root@ubuntu2404 ~]#git clone https://mirror.ghproxy.com/https://github.com/zzhang5/zooinspector.git

[root@ubuntu2404 ~]#cd zooinspector/
[root@ubuntu2404 zooinspector]#ls
pom.xml README.md src target

[root@ubuntu2404 zooinspector]#mvn clean package -Dmaven.test.skip=true
......
[WARNING] Resulting tar file can only be processed successfully by GNU compatible tar commands
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:00 min
[INFO] Finished at: 2024-10-16T16:49:04+08:00
[INFO] ------------------------------------------------------------------------

[root@ubuntu2404 zooinspector]#chmod +x zooinspector-pkg/bin/zooinspector.sh
[root@ubuntu2404 zooinspector]#./zooinspector-pkg/bin/zooinspector.sh

范例: rocky8 编译 zooinspector

#注意:只支持JDK8,不支持JDK11

[root@rocky8 ~]#yum -y install java-1.8.0-openjdk maven git
github
[root@zookeeper-node1 ~]#git clone https://github.com/zhang5/zooinspector.git

#注意:只支持JDK8,不支持JDK11
[root@rocky8 ~]#yum -y install java-1.8.0-openjdk maven git

#github
[root@zookeeper-node1 ~]#git clone https://github.com/zzhang5/zooinspector.git

#国内镜像
[root@zookeeper-node1 ~]#git clone https://gitee.com/lbtooth/zooinspector.git

[root@zookeeper-node1 ~]#cd zooinspector/

#镜像加速
[root@zookeeper-node1 zooinspector]#vim /etc/maven/settings.xml
 <mirrors>
   <!--阿里云镜像-->
   <mirror>
       <id>nexus-aliyun</id>
       <mirrorOf>*</mirrorOf>
       <name>Nexus aliyun</name>
       <url>http://maven.aliyun.com/nexus/content/groups/public</url>
   </mirror>                         
 </mirrors>

#编译,此步骤需要较长时间下载,可能数分钟
[root@zookeeper-node1 zooinspector]#mvn clean package -Dmaven.test.skip=true

image-20260406172814837

image-20260406172821758

2.3.1.2 客户端使用

[root@zookeeper-node1 zooinspector]#ls
pom.xml README.md src target

[root@zookeeper-node1 zooinspector]#ll target/ -h
total 1.4M
drwxr-xr-x 7 root root 4.0K May 11 18:08 ./
drwxr-xr-x 5 root root 4.0K May 11 18:08 ../
drwxr-xr-x 4 root root 4.0K May 11 18:08 archive-tmp/
drwxr-xr-x 4 root root 4.0K May 11 18:08 classes/
drwxr-xr-x 2 root root 4.0K May 11 18:08 maven-archiver/
drwxr-xr-x 3 root root 4.0K May 11 18:08 maven-status/
-rw-r--r-- 1 root root 134K May 11 18:08 zooinspector-1.0-SNAPSHOT.jar
-rw-r--r-- 1 root root 1.2M May 11 18:08 zooinspector-1.0-SNAPSHOT-pkg.tar
drwxr-xr-x 5 root root 4.0K May 11 18:08 zooinspector-pkg/

[root@zookeeper-node1 zooinspector]#du -sh .
7.3M .

[root@zookeeper-node1 zooinspector]#chmod +x target/zooinspector-pkg/bin/zooinspector.sh

#如果是Rocky,需要提前在windows打开Xmanager类似的软件,并执行下面命令
[root@zookeeper-node1 zooinspector]#export DISPLAY=10.0.0.1:0.0

#启动zooinspector
[root@zookeeper-node1 zooinspector]#target/zooinspector-pkg/bin/zooinspector.sh

#自动打开下面图形界面

自动打开下面图形界面

image

image

2.3.2 Windows 客户端使用

先下载并安装 JDK

注意: Oracle官网需要登录才能下载

https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html 运行下面命

#方法1
D:\技术\上课文件\消息队列与微服务文件\ZooInspector\build>java -jar zookeeper-dev-ZooInspector.jar

#方法2:
只复制targets目录中的zooinspector-pkg目录和zooinspector-1.0-SNAPSHOT-pkg.tar文件运行zooinspector-pkg\bin\zooinspector.bat文件

#方法3
[root@ubuntu2404 zooinspector]#sz target/zooinspector-1.0-SNAPSHOT-pkg.tar
#直接使用Linux上面编译生成的文件zooinspector-1.0-SNAPSHOT-pkg.tar在Windows中解压缩直接运行里面的zooinspector.bat

image

image

image

image

删除

image

2.4 Python 访问 ZooKeeper

[root@zookeeper-node1 ~]#apt update && apt -y install python3 python3-kazoo
[root@zookeeper-node1 ~]#cat zookeeper_test.py 
#!/usr/bin/python3
from kazoo.client import KazooClient

zk = KazooClient(hosts='10.0.0.101:2181')
zk.start()

# 创建节点:makepath 设置为 True ,父节点不存在则创建,其他参数不填均为默认
zk.create('/zkapp/test',b'this is a test',makepath=True)

# 操作完后关闭zk连接
data=zk.get('/zkapp/test')
print(data)

zk.stop()

[root@zookeeper-node1 ~]#chmod +x ./zookeeper_test.py
[root@zookeeper-node1 ~]#./zookeeper_test.py

2.5 Golang 访问 ZooKeeper

package main

import (
    "fmt"
    "time"

    "github.com/samuel/go-zookeeper/zk"
)

func main() {
    // 连接ZooKeeper集群
    hosts := []string{"localhost:2181"}
    conn, _, err := zk.Connect(hosts, time.Second*5)
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    // 创建节点
    path := "/test"
    data := []byte("hello world")
    flags := int32(0)
    acl := zk.WorldACL(zk.PermAll)

    _, err = conn.Create(path, data, flags, acl)
    if err != nil {
        panic(err)
    }

    // 获取节点数据
    d, _, err := conn.Get(path)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Get node %s data: %s\n", path, string(d))

    // 修改节点数据
    newData := []byte("new data")
    _, err = conn.Set(path, newData, -1)
    if err != nil {
        panic(err)
    }

    d, _, err = conn.Get(path)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Get node %s data after set: %s\n", path, string(d))

    // 删除节点
    err = conn.Delete(path, -1)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Delete node %s successfully\n", path)
}

/*
说明:
1. zk.Connect:连接ZooKeeper,超时时间5秒
2. conn.Create:创建节点,支持指定路径、数据、节点类型、权限
3. conn.Get:获取节点数据
4. conn.Set:更新节点数据,版本号-1表示不校验版本
5. conn.Delete:删除节点,版本号-1表示强制删除
6. 所有操作完成后通过defer conn.Close()关闭连接
*/