分布式协调服务-ZooKeeper
What is ZooKeeper?
ZooKeeper入门
一、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.1 | ZooKeeper1 | CentOS 7.4 | apache-zookeeper-3.5.7-bin.tar.gz | jdk-8u291-linux-x64.tar.gz |
192.168.10.2 | ZooKeeper2 | CentOS 7.4 | apache-zookeeper-3.5.7-bin.tar.gz | jdk-8u291-linux-x64.tar.gz |
192.168.10.3 | ZooKeeper3 | CentOS 7.4 | apache-zookeeper-3.5.7-bin.tar.gz | jdk-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.id
的id
一样。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 的增删改查方可图形化执行
更多推荐
所有评论(0)