一、What is ZooKeeper?

ZooKeeper官网
ZooKeeper 是一种面向分布式应用程序的分布式开源协调服务,目前属于 Apache 维护。现分布式数据一致性解决方案中可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。

ZooKeeper特点:

  • 无单点: 一个(Leader),多个(Follower)的集群,只要有半数以上节点就能存活整个集群,集群安装适合奇数台服务器。
  • 顺序一致性: 从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
  • 原子性: 所有事务请求的处理结果即为全部应用成功,否则全部应用失败,无部分结果。
  • 单个系统镜像 : 无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的(无状态)。
  • 实时性: 最新事务被成功应用,ZooKeeper 可以保证客户端立即读取到这个事务变更后最新状态的数据。
  • 可靠性: 一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。

数据模型和分层命名空间:
ZooKeeper 提供的命名空间与 Unix 文件系统的命名空间非常相似。名称是由斜杠( / )分隔的路径元素序列。每个节点称做一个 ZNode ,ZooKeeper 命名空间中的每个节点(ZNode)都由一个唯一路径标识。
在这里插入图片描述

1、ZooKeeper设计目标

ZooKeeper 简单数据模型:

  • ZooKeeper 通过树形结构进行存储数据,它由在 ZooKeeper 的说法中称为 ZNodes 数据节点组成,类似于标准文件系统与文件。
  • 与专为存储而设计的典型文件系统不同,ZooKeeper 数据保存在内存中,这意味着 ZooKeeper 可以实现高吞吐量和低延迟数字。

可配置 Cluster

  • 为保证高可用,ZooKeeper都会以奇数出现在集群中保证高可用进行复制。
    在这里插入图片描述

顺序访问

  • ZooKeeper 会在每次更新中标记一个数字,该数字反映了所有 ZooKeeper 事务的顺序。后续操作可以使用该顺序来实现。

高性能更快速

  • ZooKeeper 将数据全量存储在内存中以保持高性能,并通过服务集群来实现高可用。
  • 由于 ZooKeeper 的所有更新和删除都是基于事务的,所以其在读多写少的应用场景中有着很高的性能表现。

2、ZooKeeper核心概念

Session 会话

Session 指的是 ZooKeeper 服务器与客户端会话。当客户端(Client) 通过 TCP 长连接 连接到 ZooKeeper 服务器时,Session 开始建立连接并通过心跳检测(tickTime) 与服务器保持有效会话。通过此连接,客户端(Client) 也可以向 ZooKeeper 服务端发送请求并接受响应,同时也可以接收到 Watch 事件的通知。

当由于服务器压力太大、网络故障或是客户端(Client) 主动断开连接等各种原因导致客户端连接断开时,只要在会话超时(SessionTimeout)规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。

ZNode 数据节点

在 Zookeeper 中,数据模型由数据节点(ZNode) 组成树形结构,ZNode 是一个跟 Unix 文件系统相似的节点,可以往这个节点存储或获取数据。每一个 ZNode 默认能够存储 1MB 的数据。

ZNode节点类型:

  • 持久节点:客户端与 ZooKeeper 断开连接后,该节点依旧存在。
  • 持久循序编号节点:客户端与 ZooKeeper 断开连接后,该节点依旧存在,只是 ZooKeeper 给该节点名称进行顺序编号。
  • 临时节点:客户端与 ZooKeeper 断开连接后,该节点被删除。
  • 临时循序编号节点:客户端与 ZooKeeper 断开连接后,该节点被删除,只是 ZooKeeper 给该节点名称进行顺序编号。

Watcher

Watcher 就是 ZooKeeper 中常用的事件监听器,ZooKeeper 允许用户注册一些 Watcher,并且在一些事件特定触发时,ZooKeeper 会将通知发给客户端。该机制是 ZooKeeper 实现分布式协调服务的重要特性。

ACL

Zookeeper采用ACL(AccessControlLists)策略来进行权限控制,类似于 Unix 文件系统的权限控制。
Zookeeper 定义的5种权限。

命令作用
create创建子节点权限
read查看节点数据和子节点列表的权限
write更新节点的权限
delete删除节点的权限
admin设置节点ACL的权限

3、ZooKeeper应用场景

  • 统一命名服务: 在分布式环境下,经常需要对应用/服务进行统一命名,便于识别。
  • 统一配置管理: 将信息写入 ZooKeeper,快速同步各个节点配置文件。
  • 统一集群管理: 在分布式环境中,实时掌握每个节点的状态,ZooKeeper 可以实现实时监控节点状态变化。
  • 服务器动态上下线: 客户端能实时洞察到服务器上下线的变化,进行事件通知。
  • 软负载均衡: 在 ZooKeeper 中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求。

4、Paxos算法与Zab协议

Paxos 算法

  • Paxos 算法:一种基于消息传递且具有高度容错特性的一致性算法。
  • Paxos 算法解决的问题: 就是如何快速正确的在一个分布式系统中对某个数据值达成一致,并且保证不论发生任何异常,都不会破坏整个系统的一致性。
  • 在一个 Paxos 系统中,首先将所有节点划分为 Proposer(提议者),Acceptor(接受者),和
    Learner(学习者)。(注意:每个节点都可以身兼数职)。

Paxos 算法缺点

  • Paxos 算法缺陷: 在网络复杂的情况下,一个应用 Paxos 算法的分布式系统,可能很久无法收敛,甚至陷入活锁的情况。

  • 造成这种情况的原因是系统中有一个以上的 Proposer(提议者),多个 Proposer(提议者) 相互争夺 Acceptor(接收者),造成迟迟无法达成一致的情况。针对这种情况,一种改进的 Paxos 算法被提出:从系统中选出一个节点作为 Leader,只有 Leader 能够发起提案。这样,一次 Paxos 流程中只有一个 Proposer,不会出现活锁的情况。

Zab 协议

  • Zab 算法: Zab 借鉴了 Paxos 算法,是特别为 ZooKeeper 设计的支持崩溃恢复的原子广播协议。基于该协议,ZooKeeper 设计为只有一台客户端(Leader)负责处理外部的写事务请求,然后Leader 客户端将数据同步到其他 Follower 节点。即 ZooKeeper 只有一个 Leader 可以发起提案。
  • Zab 协议内容: Zab 协议包括两种基本的模式:消息广播、崩溃恢复。

CAP理论
CAP理论告诉我们,一个分布式系统不可能同时满足以下三种。

  • 一致性(C:Consistency)
    在分布式环境中,一致性是指数据在多个副本之间是否能够保持数据一致的特性。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态。
  • 可用性(A:Available)
    可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。
  • 分区容错性(P:Partition Tolerance)
    分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。

这三个基本需求,最多只能同时满足其中的两项,因为P是必须的,因此往往选择就在CP或者AP中。

ZooKeeper保证的是CP

  • ZooKeeper 不能保证每次服务请求的可用性。(注:在极端环境下,ZooKeeper 可能会丢弃一些请求,消费者程序需要重新请求才能获得结果)。所以说,ZooKeeper 不能保证服务可用性。
  • 进行 Leader 选举时集群都是不可用。

二、ZooKeeper 集群安装

部署准备

IP地址主机名操作系统ZooKeeper版本(官方下载地址)JDK版本(国内下载地址)
192.168.10.1ZooKeeper1CentOS 7.4apache-zookeeper-3.5.7-bin.tar.gzjdk-8u291-linux-x64.tar.gz
192.168.10.2ZooKeeper2CentOS 7.4apache-zookeeper-3.5.7-bin.tar.gzjdk-8u291-linux-x64.tar.gz
192.168.10.3ZooKeeper3CentOS 7.4apache-zookeeper-3.5.7-bin.tar.gzjdk-8u291-linux-x64.tar.gz

本次采用 ZooKeeper3.5.7 版本,JDK1.8.0_291。官方依赖查询

JDK安装

[root@ZooKeeper1 ~]# mkdir /zk/
[root@ZooKeeper1 ~]# ls /zk
jdk-8u291-linux-x64.tar.gz
[root@ZooKeeper1 zk]# tar zxvf jdk-8u291-linux-x64.tar.gz
[root@ZooKeeper1 zk]# ls
jdk1.8.0_291  jdk-8u291-linux-x64.tar.gz
[root@ZooKeeper1 zk]# cat << EOF >>  /etc/profile.d/jdk.sh
> JAVA_HOME=/zk/jdk1.8.0_291
> PATH=\$JAVA_HOME/bin:\$PATH
> export JAVA_HOME PATH
> EOF
[root@ZooKeeper1 zk]# source /etc/profile
[root@ZooKeeper1 zk]# java -version
java version "1.8.0_291"
Java(TM) SE Runtime Environment (build 1.8.0_291-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)

1、ZooKeeper 单机安装

[root@ZooKeeper1 zk]# wget http://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/apache-zookeeper-3.5.7-bin.tar.gz
[root@ZooKeeper1 zk]# tar zxvf apache-zookeeper-3.5.7-bin.tar.gz
[root@ZooKeeper1 zk]# ll
总用量 150636
drwxr-xr-x 6 root root       134 5月  12 19:43 apache-zookeeper-3.5.7-bin
-rw-r--r-- 1 root root   9311744 5月  12 19:43 apache-zookeeper-3.5.7-bin.tar.gz
drwxr-xr-x 8 root root       273 4月   8 2021 jdk1.8.0_291
-rw-r--r-- 1 root root 144935989 5月  12 19:21 jdk-8u291-linux-x64.tar.gz
[root@ZooKeeper1 zk]# mkdir apache-zookeeper-3.5.7-bin/data
[root@ZooKeeper1 zk]# cat <<EOF >> apache-zookeeper-3.5.7-bin/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/zk/apache-zookeeper-3.5.7-bin/data
clientPort=2181
EOF

配置注解:

  • tickTime :通信心跳时间,ZooKeeper Server 与 Client 心跳时间,单位毫秒
  • initLimit:Leader 和 Follower 间初始通信时限,单位次数,(Leader 和 Follower 初始连接时能容忍的最多心跳数(tickTime的数量))。
  • syncLimit:Leader 和 Follower 间同步通信时限,单位次数(Leader 和 Follower 之间通信时间超过syncLimit * tickTime,Leader认为Follwer死掉并删除Follwer)。
  • dataDir:保存 ZooKeeper 内存数据库中的快照信息(当未配置 dataLogDir 参数时,日志信息也会存放到此目录)。
  • clientPort:ZooKeeper 监听的端口,用于客户端连接使用。

ZooKeeper 状态查询

[root@ZooKeeper1 zk]# apache-zookeeper-3.5.7-bin/bin/zkServer.sh start			#启动
[root@ZooKeeper1 zk]# apache-zookeeper-3.5.7-bin/bin/zkServer.sh restart		#重启
[root@ZooKeeper1 zk]# apache-zookeeper-3.5.7-bin/bin/zkServer.sh status			#状态检查
[root@ZooKeeper1 zk]# apache-zookeeper-3.5.7-bin/bin/zkServer.sh help			#查看命令
ZooKeeper JMX enabled by default
Using config: /zk/apache-zookeeper-3.5.7-bin/bin/../conf/zoo.cfg
Usage: apache-zookeeper-3.5.7-bin/bin/zkServer.sh [--config <conf-dir>] {start|start-foreground|stop|restart|status|print-cmd}
[root@ZooKeeper1 zk]# apache-zookeeper-3.5.7-bin/bin/zkCli.sh -server 127.0.0.1	#ZooKeeper客户端连接

在这里插入图片描述

2、ZooKeeper 集群安装

集群角色

角色作用
Leader提供读写服务,保证集群事务处理顺序性以及集群内部各服务器调度
Follower提供读写服务,并定期向 Leader 汇报自己的节点状态(同时也参加 过半写成功的策略Leader 的选举
Observer提供读写服务,并定期向 Leader 汇报自己的节点状态(与 Follower 区别是不参与选举于策略,可以在不影响写性能的情况下提升集群的读性能)
Looking寻找 Leader 状态,处于该状态需要进入选举流程

1、将 JDK 与 ZooKeeper 传给另外两台

[root@ZooKeeper1 zk]# for i in {2,3}
do
scp -r /zk/{jdk1.8.0_291,apache-zookeeper-3.5.7-bin} root@192.168.10.$i:/zk/
done
[root@ZooKeeper2 zk]# source /etc/profile		#生效
[root@ZooKeeper2 zk]# jps
15505 Jps
[root@ZooKeeper3 zk]# source /etc/profile		#生效
[root@ZooKeeper3 zk]# jps
15513 Jps

2、将 ZooKeeper 配置传给另外两台

[root@ZooKeeper1 zk]# cat << EOF >> apache-zookeeper-3.5.7-bin/conf/zoo.cfg 
> server.1=192.168.10.1:2888:3888
> server.2=192.168.10.2:2888:3888
> server.3=192.168.10.3:2888:3888
> EOF
[root@ZooKeeper1 zk]# for i in {2,3}
do
scp /zk/apache-zookeeper-3.5.7-bin/conf/zoo.cfg root@192.168.10.$i:/zk/apache-zookeeper-3.5.7-bin/conf/
done

3、创建 myid 文件

[root@ZooKeeper1 zk]# echo "1" > /zk/apache-zookeeper-3.5.7-bin/data/myid
[root@ZooKeeper2 zk]# echo "2" > /zk/apache-zookeeper-3.5.7-bin/data/myid
[root@ZooKeeper3 zk]# echo "3" > /zk/apache-zookeeper-3.5.7-bin/data/myid

配置参数解读
server.A=B:C:D

  • A:是一个数字,表示这个是第几台服务器,在 dataDir 目录下;需要确保每台服务器 myid 不重复,并且和本机的 zoo.cfg 中的 server.idid 一样。
  • B:服务器地址。
  • C:是服务器中的 Follower 与集群中的 Leader 服务器交换信息的端口。
  • D:是集群中的 Leader 服务器宕机,需要用此端口来重新选举出一个新的 Leader,此端口就是用来执行选举时服务器相互通信的端口。

4、启动 ZooKeeper 集群

[root@ZooKeeper1 zk]# for i in {1,2,3}
do
ssh root@192.168.10.$i /zk/apache-zookeeper-3.5.7-bin/bin/zkServer.sh start
done

在这里插入图片描述

5、创建 ZooKeeper 状态查询脚本

#!/bin/bash
case $1 in
"start"){
for i in {1,2,3}
do
 echo ---------- ZooKeeper $i 启动 ------------
ssh root@192.168.10.$i "/zk/apache-zookeeper-3.5.7-bin/bin/zkServer.sh start"
done
};;
"stop"){
for i in {1,2,3}
do
 echo ---------- ZooKeeper $i 停止 ------------ 
ssh root@192.168.10.$i "/zk/apache-zookeeper-3.5.7-bin/bin/zkServer.sh stop"
done
};;
"status"){
for i in {1,2,3}
do
 echo ---------- ZooKeeper $i 状态 ------------ 
ssh root@192.168.10.$i "/zk/apache-zookeeper-3.5.7-bin/bin/zkServer.sh status"
done
};;
"restart"){
for i in {1,2,3}
do
 echo ---------- ZooKeeper $i 重启 ------------
ssh root@192.168.10.$i "/zk/apache-zookeeper-3.5.7-bin/bin/zkServer.sh restart"
done
};;
esac

在这里插入图片描述

3、ZooKeeper 操作

ZooKeeper 选举机制

  • SID:服务器ID。用来唯一标识每台 ZooKeeper 集群中的机器,每台机器不能重复,和 myid 一致。
  • ZXID:事务ID。ZXID 是一个事务 ID,用来标识每一次服务器状态的变更。在某一时刻,集群中的每台机器的 ZXID 值不一定完全一致,这和 ZooKeeper 服务器对于客户端更新请求的处理逻辑有关。
  • Epoch:每个 Leader 任期的代号。没有 Leader 时同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加。

非第一次启动选举 Leader 规则

  • 1、Epoch 大的直接胜出
  • 2、Epoch 相同,事务 ID 大的胜出
  • 3、事务 ID 相同,服务器 ID 大的胜出

ZooKeeper 操作

[root@ZooKeeper1 zk]# apache-zookeeper-3.5.7-bin/bin/zkCli.sh -server 127.0.0.1:2181		#启动 ZooKeeper 客户端
[zk: 127.0.0.1:2181(CONNECTED) 0] help														#显示所有命令使用
[zk: 127.0.0.1:2181(CONNECTED) 32] ls /		#查看当前 ZNode 中所包含的内容
[zookeeper]
[zk: 127.0.0.1:2181(CONNECTED) 33] ls -s /	#查看当前 ZNode 详细数据
[zookeeper]cZxid = 0x0						#cZxid:创建节点的事务 zxid
ctime = Thu Jan 01 08:00:00 CST 1970		#ctime:ZNode 被创建的毫秒数(默认从 1970 年开始)
mZxid = 0x0									#mZxid:ZNode 最后更新的事务 zxid
mtime = Thu Jan 01 08:00:00 CST 1970		#mtime:ZNode 最后修改的毫秒数(默认从 1970 年开始)
pZxid = 0x10000000f							#pZxid:ZNode 最后更新的子节点 zxid
cversion = 1								#cversion:ZNode 子节点变化号,ZNode 子节点修改次数
dataVersion = 0								#dataVersion:ZNode 数据变化号
aclVersion = 0								#aclVersion:ZNode 访问控制列表的变化号
ephemeralOwner = 0x0						#ephemeralOwner:如果是临时节点,这个是 ZNode 拥有者的 Session id。如果不是临时节点则是 0。
dataLength = 0								#dataLength:ZNode 的数据长度
numChildren = 1								#numChildren:ZNode 子节点数量

在这里插入图片描述
1、分别创建2个普通节点(永久节点 + 不带序号)

[zk: 127.0.0.1:2181(CONNECTED) 9] create /xy "xy"								#创建永久节点
Created /xy
[zk: 127.0.0.1:2181(CONNECTED) 10] create /xy/xy1 "xy1"
Created /xy/xy1
[zk: 127.0.0.1:2181(CONNECTED) 11] set /xy/xy1 "xy111111111111111111111111111"	#修改值
[zk: 127.0.0.1:2181(CONNECTED) 12] get /xy/xy1									#查看值
xy111111111111111111111111111

在这里插入图片描述

2、获得节点的值

[zk: 127.0.0.1:2181(CONNECTED) 46] get /xy				#获取节点值
xy
[zk: 127.0.0.1:2181(CONNECTED) 47] get /xy/xy1
xy1
[zk: 127.0.0.1:2181(CONNECTED) 48] get -s /xy/xy1		#查看 ZNode 详细信息
xy1
cZxid = 0x100000012
ctime = Fri May 13 23:06:07 CST 2022
mZxid = 0x100000012
mtime = Fri May 13 23:06:07 CST 2022
pZxid = 0x100000012
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0

在这里插入图片描述

3、创建带序号的节点(永久节点 + 带序号)

[zk: 127.0.0.1:2181(CONNECTED) 14] create /xy2						#创建普通节点
Created /xy2
[zk: 127.0.0.1:2181(CONNECTED) 15] create -s /xy2/xy22 "xy22"		#永久带序号 ZNode
Created /xy2/xy220000000000
[zk: 127.0.0.1:2181(CONNECTED) 16] create -s /xy2/xy22 "xy22"
Created /xy2/xy220000000001
[zk: 127.0.0.1:2181(CONNECTED) 17] create -s /xy2/xy22 "xy22"
Created /xy2/xy220000000002

在这里插入图片描述
4、创建短暂节点(短暂节点 + 不带序号 & 带序号)

[zk: 127.0.0.1:2181(CONNECTED) 20] create /xy3 "xy3"										#创建永久节点
Created /xy3
[zk: 127.0.0.1:2181(CONNECTED) 21] create -e /xy3/xy33 "xy33"								#创建临时节点
Created /xy3/xy33
[zk: 127.0.0.1:2181(CONNECTED) 22] create -e -s /xy3/xy33 "xy33"							#创建临时带序号节点
Created /xy3/xy330000000001
[zk: 127.0.0.1:2181(CONNECTED) 23] ls /xy3													#查看临时节点
[xy33, xy330000000001]
[zk: 127.0.0.1:2181(CONNECTED) 24] quit														#退出 ZooKeeper 客户端
[root@ZooKeeper1 zk]# apache-zookeeper-3.5.7-bin/bin/zkCli.sh -server 127.0.0.1:2181		#重新进入
[zk: 127.0.0.1:2181(CONNECTED) 0] ls /xy3													#查看发现已经消失
[]

在这里插入图片描述
5、监听节点值变化

192.168.10.1
[zk: 127.0.0.1:2181(CONNECTED) 0] get -w /xy
xy
[zk: 127.0.0.1:2181(CONNECTED) 1] 
WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/xy
192.168.10.2
[zk: 127.0.0.1:2181(CONNECTED) 1] set /xy "xyxyxy"
[zk: 127.0.0.1:2181(CONNECTED) 2] set /xy "xyxyxyxyxyxy"

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
6、节点删除与查看

[zk: 127.0.0.1:2181(CONNECTED) 7] delete /xy/xy1			#删除节点
[zk: 127.0.0.1:2181(CONNECTED) 8] deleteall /xy2			#递归删除
[zk: 127.0.0.1:2181(CONNECTED) 8] stat /					#查看节点状态

在这里插入图片描述
7、ZooInspector 工具介绍

  • 1、配置Windows JDK。
  • 2、解压 ZooInspector.rar 到任意路径,ZooInspector.rar 包以上传资源。
  • 3、win+r 输入cmd 进入命令行工具,进入指定路径,输入java -jar zookeeper-dev-ZooInspector.jar 运行。

连接 ZooKeeper 地址方可操作,格式 IP:Port
在这里插入图片描述
连接上 ZooKeeper 的增删改查方可图形化执行
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐