zookeeper简介

1. What is ZooKeeper?

ZooKeeper 是 Apache 软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册。设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。

Zookeeper官网:

Zookeeper官方文档:

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable. Because of the difficulty of implementing these kinds of services, applications initially usually skimp on them, which make them brittle in the presence of change and difficult to manage. Even when done correctly, different implementations of these services lead to management complexity when the applications are deployed.

Learn more about ZooKeeper on the ZooKeeper Wiki.

简而言之:ZooKeeper是一个用于维护配置信息、命名、提供分布式同步和提供组服务的集中式服务。

1.2设计目标

1.2.1 ZooKeeper is simple

ZooKeeper 允许分布式进程通过类似于标准文件系统组织的共享分层命名空间相互协调。命名空间由数据寄存器组成——用 ZooKeeper 的说法称为 znodes——它们类似于文件和目录。与为存储而设计的典型文件系统不同,ZooKeeper 数据保存在内存中,这意味着 ZooKeeper 可以实现高吞吐量和低延迟数。

ZooKeeper 实现非常重视高性能、高可用性、严格有序的访问。ZooKeeper 的性能方面意味着它可以用于大型分布式系统。可靠性方面使其不会成为单点故障。严格的排序意味着可以在客户端实现复杂的同步原语

1.2.2 ZooKeeper is replicated.

就像它协调的分布式进程一样,ZooKeeper 本身旨在通过一组称为集成的主机进行复制。

动物园管理员服务

构成 ZooKeeper 服务的服务器必须相互了解。它们在内存中维护状态数据,以及持久存储中的事务日志和快照。只要大多数服务器可用,ZooKeeper 服务就可用。

客户端连接到单个 ZooKeeper 服务器。客户端维护一个 TCP 连接,通过它发送请求、获取响应、获取监视事件和发送心跳。如果与服务器的 TCP 连接中断,客户端将连接到另一台服务器。

1.2.3 ZooKeeper is ordered

ZooKeeper 用反映所有 ZooKeeper 事务顺序的数字标记每个更新。后续操作可以使用该顺序来实现更高级别的抽象,例如同步原语。

1.2.4 ZooKeeper is fast

它在“读主导”工作负载中特别快。ZooKeeper 应用程序在数千台机器上运行,它在读取比写入更常见的情况下表现最佳,比率约为 10:1。

2.Zookeeper安装

本文省略Zookeeper安装具体教程,如果有兴趣查找以上资料进行安装。

zoo.cfg相关参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# The number of milliseconds of each tick
# 这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳,以毫秒为单位。
tickTime=2000

# The number of ticks that the initial
# synchronization phase can take
# 这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 52000=10 秒
initLimit=10

# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5

# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
# 顾名思义就是 Zookeeper 保存数据的目录,默认情况下
dataDir=D:\software\zookeeper\apache-zookeeper-3.7.0\data

#Zookeeper 将写数据的日志文件保存在这个目录里。
dataLogDir=D:\software\zookeeper\apache-zookeeper-3.7.0\log

# the port at which the clients will connect
# 这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求
clientPort=2181

# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60

# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.

# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance

# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

## Metrics Providers
# https://prometheus.io Metrics Exporter
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true

3.Zookeeper概念

3.1 数据模型和分层命名空间

ZooKeeper 中的数据模型是一种树形结构,非常像电脑中的文件系统,有一个根文件夹,下面还有很多子文件夹。ZooKeeper 的数据模型也具有一个固定的根节点(/),我们可以在根节点下创建子节点,并在子节点下继续创建下一级节点。ZooKeeper 树中的每一层级用斜杠(/)分隔开,且只能用绝对路径(如“get /work/task1”)的方式查询 ZooKeeper 节点,而不能使用相对路径。具体的结构看看下面这张图:

image

ZooKeeper 数据模型的结构与Unix文件系统很类似,每个节点称作一个ZNode,ZNode 是以 key-value 形式存在的。名称 key 由斜线 / 分割的一系列路径元素,zookeeper 名称空间中的每个节点都是由一个路径标识。

注意:ZooKeeper 不使用相对路径。所以以下是无效的:“/a/b/./c”或“/a/b/../c”。

3.2 节点和临时节点

与标准文件系统不同,ZooKeeper 命名空间中的每个节点都可以有与其关联的数据以及子节点。这就像拥有一个允许文件也可以是目录的文件系统。(ZooKeeper 旨在存储协调数据:状态信息、配置、位置信息等,因此每个节点存储的数据通常很小,在字节到千字节范围内。)我们使用术语 znode 来明确我们正在谈论 ZooKeeper 数据节点。

Znodes 维护一个统计结构,其中包括数据更改的版本号、ACL 更改和时间戳,以允许缓存验证和协调更新。每次 znode 的数据更改时,版本号都会增加。例如,每当客户端检索数据时,它也会收到数据的版本。

存储在命名空间中每个 znode 的数据是原子读取和写入的。读取获取与 znode 关联的所有数据字节,写入替换所有数据。每个节点都有一个访问控制列表 (ACL),用于限制谁可以做什么。

ZooKeeper 也有临时节点的概念。只要创建 znode 的会话处于活动状态,这些 znode 就会存在。当会话结束时,znode 将被删除。

3.3 条件更新和监视

ZooKeeper 支持watches的概念。客户端可以在 znode 上设置监视。当 znode 更改时,将触发并删除 watch。触发监视时,客户端会收到一个数据包,说明 znode 已更改。如果客户端和其中一个 ZooKeeper 服务器之间的连接断开,客户端将收到本地通知。

3.6.0 中的新增功能:客户端还可以在 znode 上设置永久的递归监视,这些监视在触发时不会被删除,并且会递归地触发已注册 znode 以及任何子 znode 上的更改。

3.4 保证

ZooKeeper 非常快速且非常简单。但是,由于它的目标是成为构建更复杂服务(例如同步)的基础,因此它提供了一组保证。这些都是:

  • 顺序一致性——来自客户端的更新将按照它们发送的顺序应用。
  • 原子性——更新要么成功要么失败。没有部分结果。
  • 单一系统映像——无论连接到哪个服务器,客户端都将看到相同的服务视图。即,即使客户端故障转移到具有相同会话的不同服务器,客户端也永远不会看到系统的旧视图。
  • 可靠性——应用更新后,它将一直持续到客户端覆盖更新为止。
  • 及时性——系统的客户视图保证在特定时间范围内是最新的。

3.5 Simple Api

ZooKeeper 的设计目标之一是提供一个非常简单的编程接口。因此,它仅支持这些操作:

  • create:在树中的某个位置创建一个节点
  • delete : 删除一个节点
  • exists : 测试节点是否存在于某个位置
  • 获取数据:从节点读取数据
  • 设置数据:将数据写入节点
  • get children:检索节点的子节点列表
  • sync:等待数据传播

4.Zookeeper节点

4.1 节点的状态结构

节点称为 ZNode。每个 ZNode 有一个名称标识,即树根到该节点的路径(用 “/” 分隔),ZooKeeper 树中的每个节点都可以拥有子节点,这与文件系统的目录树类似。

上图中,每一个节点都是一个ZNode,每个ZNode都会保存自己的数据内容和一系列属性信息,维护一个stat结构。比如上面我们创建的works节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
[zk: localhost:2181(CONNECTED) 15] stat /works
cZxid = 0x4
ctime = Mon Mar 06 16:07:21 CST 2023
mZxid = 0x4
mtime = Mon Mar 06 16:07:21 CST 2023
pZxid = 0x7
cversion = 3
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 3
[zk: localhost:2181(CONNECTED) 16]

其中每个字段的含义为:

表.png

在zookeeper中,事务是指能够改变zookeeper服务器状态的操作,称为事务操作和更新操作。一般包括数据节点的创建与删除、数据节点内容更新等操作。

每一次事务请求,zk都会为其分配一个全局唯一的事务id,用ZXID表示,通常是一个64位数字。每一个ZXID对应一次更新更新操作。

为什么 ZooKeeper 不能采用相对路径查找节点呢?

因为 ZooKeeper 大多是应用场景是定位数据模型上的节点,并在相关节点上进行操作。ZooKeeper 在底层实现的时候,使用了一个 hashtable,即 hashtableConcurrentHashMap<String, DataNode> nodes ,用节点的完整路径来作为 key 存储节点数据。这样就大大提高了 ZooKeeper 的性能。

上述众多节点特性,使得 zookeeper 能开发不出不同的经典应用场景,比如:

    1. 数据发布/订阅
    1. 负载均衡
    1. 分布式协调/通知
    1. 集群管理
    1. 集群管理
    1. master 管理
    1. 分布式锁
    1. 分布式队列

4.2 节点类型

与标准文件系统不同,ZooKeeper 命名空间中的每个节点都可以有与其关联的数据以及子节点。这就像拥有一个允许文件也可以是目录的文件系统。(ZooKeeper 旨在存储协调数据:状态信息、配置、位置信息等,因此每个节点存储的数据通常很小,在字节到千字节范围内。)我们使用术语znode明确我们正在谈论 ZooKeeper 数据节点。

Znodes 维护一个统计结构,其中包括数据更改的版本号、ACL 更改和时间戳,以允许缓存验证和协调更新。每次 znode 的数据更改时,版本号都会增加。例如,每当客户端检索数据时,它也会收到数据的版本。

存储在命名空间中每个 znode 的数据是原子读取和写入的。读取获取与 znode 关联的所有数据字节,写入替换所有数据。每个节点都有一个访问控制列表 (ACL),用于限制谁可以做什么

ZooKeeper 由节点来存储信息,ZooKeeper 中的数据节点也分为 持久节点临时节点有序节点三种类型:

4.2.1 持久节点

持久节点,这种节点也是在 ZooKeeper 最为常用的,持久节点一旦将节点创建为持久节点,该数据节点会一直存储在 ZooKeeper 服务器上,即使创建该节点的客户端与服务端的会话关闭了,该节点依然不会被删除。如果我们想删除持久节点,就要显式调用 delete 函数进行删除操作。

### 4.2.2 临时节点

ZooKeeper 也有临时节点的概念。只要创建 znode 的会话处于活动状态,这些 znode 就会存在。当会话结束时,znode 将被删除。

临时节点的一个最重要的特性就是临时性。所谓临时性是指,如果将节点创建为临时节点,那么该节点数据不会一直存储在 ZooKeeper 服务器上。当创建该临时节点的客户端会话因超时或发生异常而关闭时,该节点也相应在 ZooKeeper 服务器上被删除。同样,我们可以像删除持久节点一样主动删除临时节点。

在平时的开发中,我们可以利用临时节点的这一特性来做服务器集群内机器运行情况的统计,将集群设置为“/servers”节点,并为集群下的每台服务器创建一个临时节点“/servers/host”,当服务器下线时该节点自动被删除,最后统计临时节点个数就可以知道集群中的运行情况。如下图所示:

image

临时节点不允许有子节点,因为它随时可能被删除。

### 4.2.3 有序节点

其实有序节点并不算是一种单独种类的节点,而是在之前提到的持久节点和临时节点特性的基础上,增加了一个节点有序的性质。所谓节点有序是说在我们创建有序节点的时候,ZooKeeper 服务器会自动使用一个单调递增的数字作为后缀,追加到我们创建节点的后边。例如一个客户端创建了一个路径为 works/task- 的有序节点,那么 ZooKeeper 将会生成一个序号并追加到该节点的路径后,最后该节点的路径为 works/task-1。通过这种方式我们可以直观的查看到节点的创建顺序。

因此可以分为:

  • 持久节点:节点被创建后会一直存在服务器,除非主动进行ZNode删除操作,主动清除。否则一直被保存
  • 持久顺序节点:创建节点时会在节点名后面加上一个数字后缀来表示顺序,和持久节点特性一样
  • 临时节点:生命周期和客户端会话绑在一起,客户端会话结束,节点会被删除;不能创建子节点
  • 临时顺序节点:有顺序的临时节点

到目前为止我们知道在 ZooKeeper 服务器上存储数据的基本信息,知道了 ZooKeeper 中的数据节点种类有持久节点和临时节点等。上述这几种数据节点虽然类型不同,但 ZooKeeper 中的每个节点都维护有这些内容:一个二进制数组(byte data[]),用来存储节点的数据、ACL 访问控制信息、子节点数据(因为临时节点不允许有子节点,所以其子节点字段为 null),除此之外每个数据节点还有一个记录自身状态信息的字段 stat。

5.Zookeeper命令

命令:

为了后续讲解,此处只展示常用的基础命令。

  • connect host:port 连接zookeeper

connect 127.0.0.1:2181

可选的“chroot”后缀也可以附加到连接字符串。这将运行客户端命令,比如我们运行:

connect 127.0.0.1:2181/works

其中客户端将根于此路径,所有路径都将相对于此根

  • ls 查看某个路径下目录列表,path:代表路径。

ls path

  • ls2 查看某个路径下目录列表,它比 ls 命令列出更多的详细信息

ls2 path

  • get 用于获取节点数据和状态信息,[watch]:对节点进行事件监听。

get path [watch]

节点监听:如果有另一个终端对该节点进行了修改,则监听此节点的终端会得到事件通知

  • stat 查看节点状态信息。

stat path [watch]

  • create 用于创建节点并赋值。

create [-s] [-e] path data acl

  • [-s] [-e]:-s 和 -e 都是可选的,-s 代表顺序节点, -e 代表临时节点,
  • path:指定要创建节点的路径,比如 /runoob
  • data:要在此节点存储的数据。
  • acl:访问权限相关,默认是 world,相当于全世界都能访问。

注意其中 -s 和 -e 可以同时使用的,并且临时节点不能再创建子节点。

  • set 修改节点存储的数据。[version]:可选项,版本号(可用作乐观锁)。

set path data [version]

  • delete 删除某节点

delete path [version]

image

举例,现在我们创建上图节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] create /locks
Created /locks
[zk: localhost:2181(CONNECTED) 2] create /works
Created /works
[zk: localhost:2181(CONNECTED) 3] create /works/test1
Created /works/test1
[zk: localhost:2181(CONNECTED) 4] create /works/test2
Created /works/test2
[zk: localhost:2181(CONNECTED) 5] create /works/test3
Created /works/test3
[zk: localhost:2181(CONNECTED) 6] ls /
[locks, works, zookeeper]
[zk: localhost:2181(CONNECTED) 7]

6.Read more

:lollipop::https://www.runoob.com/w3cnote/zookeeper-znode-data-model.html


博客说明

文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,不用于任何的商业用途。如有侵权,请联系本人删除。谢谢!


zookeeper简介
https://nanchengjiumeng123.top/2022/09/11/framework/zookeeper/2022-09-11_zookeeper简介/
作者
Yang Xin
发布于
2022年9月11日
许可协议