分布式协调服务-ZooKeeper

加粗样式

ZooKeeper入门

  • 一、What is ZooKeeper?
    • 1、ZooKeeper设计目标
    • 2、ZooKeeper核心概念
      • Session 会话
      • ZNode 数据节点
      • Watcher
      • ACL
    • 3、ZooKeeper应用场景
    • 4、Paxos算法与Zab协议
  • 二、ZooKeeper 集群安装
    • 1、ZooKeeper 单机安装
    • 2、ZooKeeper 集群安装
    • 3、ZooKeeper 操作


一、What is ZooKeeper?

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

ZooKeeper特点:

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

数据模型和分层命名空间:
ZooKeeper 提供的命名空间与 Unix 文件系统的命名空间非常相似。名称是由斜杠( / )分隔的路径元素序列。每个节点称做一个 ZNode ,ZooKeeper 命名空间中的每个节点(ZNode)都由一个唯一路径标识。
分布式协调服务-ZooKeeper_第1张图片

1、ZooKeeper设计目标

ZooKeeper 简单数据模型:

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

可配置 Cluster

  • 为保证高可用,ZooKeeper都会以奇数出现在集群中保证高可用进行复制。
    分布式协调服务-ZooKeeper_第2张图片

顺序访问

  • 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 <> 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 ] {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客户端连接

分布式协调服务-ZooKeeper_第3张图片

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

分布式协调服务-ZooKeeper_第4张图片

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

分布式协调服务-ZooKeeper_第5张图片

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 子节点数量

分布式协调服务-ZooKeeper_第6张图片
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

分布式协调服务-ZooKeeper_第7张图片

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

分布式协调服务-ZooKeeper_第8张图片

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

分布式协调服务-ZooKeeper_第9张图片
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													#查看发现已经消失
[]

分布式协调服务-ZooKeeper_第10张图片
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"

分布式协调服务-ZooKeeper_第11张图片

分布式协调服务-ZooKeeper_第12张图片
分布式协调服务-ZooKeeper_第13张图片
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 /					#查看节点状态

分布式协调服务-ZooKeeper_第14张图片
7、ZooInspector 工具介绍

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

连接 ZooKeeper 地址方可操作,格式 IP:Port
分布式协调服务-ZooKeeper_第15张图片
连接上 ZooKeeper 的增删改查方可图形化执行
分布式协调服务-ZooKeeper_第16张图片

你可能感兴趣的