ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【深入 ZooKeeper】— ZooKeeper 一文通

2022-06-10 19:02:39  阅读:179  来源: 互联网

标签:一文 ZooKeeper Watcher 深入 客户端 数据 节点 分布式


ZooKeeper 为分布式应用提供了高效且可靠的分布式协调服务,例如统一命名服务、配置管理和分布式锁等分布式的基础服务。另外,在解决分布式一致性方面,ZooKeeper 并没有直接采用 Paxos 算法,而是采用一种被称为 ZAB(ZooKeeper Atomic Broadcast)的一致性协议。

基本概念

ZooKeeper 有以下几个核心概念

集群角色

ZooKeeper 中存在三种角色:Leader、Follower 和 Observer。ZooKeeper 集群中的所有机器通过一个 Leader 选举过程来选定一台被称为“Leader”的机器,Leader 服务器为客户端提供读和写服务。除 Leader 外,其他机器包括 Follower 和 Observer。Follower 和 Observer 都能提供读服务,唯一的区别在于,Observer 机器不参与 Leader 选举过程,也不参与写操作的“过半写成功”的策略。

会话

Session 是指客户端会话,与之相关的便是客户端连接。在 ZooKeeper 中,一个客户端连接是指客户端和服务器之间的一个 TCP 长连接。客户端启动的时候,首先会与服务器建立一个 TCP 连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的 Watch 事件通知。Session 的 SessionTimeout 值用来设置一个客户端会话的超时时间。当由于各种原因(服务器压力太大、网络故障或是客户端主动断开)导致客户端连接断开时,只要在 sessionTimeout 规定时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。

数据节点

在 ZooKeeper 中,节点分为两种

  • 组成集群的每一台机器
  • 数据模型中的数据单元

对于第一种我们好理解,也就是分布式中的机器节点。第二种便是 ZooKeeper 中的数据存储模型,称之为数据节点——ZNode。ZooKeeper 将所有的数据存储在内存中,数据模型是一棵树(ZNode Tree),由斜杠(/)进行分割的路径,就是一个 ZNode,例如 /root/path。每个节点上都会保存自己的数据内容,同时还有保存一系列属性信息。

ZNode 分为持久节点和临时节点两类。所谓持久节点是指一旦这个 ZNode 被创建了,除非主动进行 ZNode 的移除操作,否则这个 ZNode 将一直保存在 ZooKeeper 上。而临时节点不一样,它的生命周期和客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。

ZooKeeper 还允许用户为每个节点添加一个特殊的属性:SEQUENTIAL。一旦节点被标记上这个属性,那么在这个节点被创建的时候,ZooKeeper 会自动在其节点后面追加上一个整型数字,这个整型数字是一个由父节点维护的自增数字。

所以,ZooKeeper 中的 ZNode 有以下 4 中类型

  • 持久(PERSISTENT)
  • 持久顺序(PERSISTENT_SEQUENTIAL)
  • 临时(EPHEMERAL)
  • 临时顺序(EPHEMERAL_SEQUENTIAL)

需要注意的是,ZooKeeper 规定不能基于临时节点来创建子节点,也就是说临时节点只能作为叶子节点。

版本

ZooKeeper 中为数据节点引入了版本的概念,每个数据节点都具有三种类型的版本信息,分别是 version、cversion 和 aversion,对数据节点的任何更新操作都会引起版本号的变化。ZooKeeper 为每个数据节点维护一个叫做 Stat 的数据结构,Stat 中记录了这三个数据版本,版本信息介绍如下

版本类型 说明
version 当前数据节点数据内容的版本号
cversion 当前数据节点子节点的版本号
aversion 当前数据节点 ACL 变更版本号

ZooKeeper 中的版本概念和传统意义上的软件版本有很大的区别,它表示的是对数据节点的数据内容、子节点列表,或是节点 ACL 信息的修改次数。举个栗子,节点 /somelogs/article 被创建的时候,version 为0,表示该节点从创建以来,被修改了 0 次。如果现在对该节点内容进行修改,version 则变成 1。这里需要注意的是,version 表示的是修改的次数,跟修改的数据内容没关系。也就是说,即使两次更新后,数据内容没有发现变化,version 依旧会变。

那 ZooKeeper 引入版本的作用是什么呢?大概你也猜到了,就是乐观锁了。不管是数据库的乐观锁,还是 JDK 中 Unsafe 类的 compareAndSwap 操作,都是类似的思想。ZooKeeper 在每一次数据更新的时候,都会把当前请求的版本和服务器上对应数据节点的最新版本作比较,如果不一致,将会抛出 BadVersionException 异常。当然,如果在更新的时候指定 version 为 -1,表示客户端想忽略版本比较,直接基本当前最新版本进行更新。数据更新源代码如下

version = setDataRequest.getVersion();
int currentVersion = nodeRecord.stat.getVersion();
if (version != -1 && version != currentVersion) {
    throw new KeeperException.BadVersionException(path);
}
version = currentVersion + 1;

一句话概括版本的作用:保证分布式数据原子性操作

Watcher

ZooKeeper 可以提供了分布式数据的发布/订阅功能。一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能够让多个订阅者同时监听某一个主题对象,当这个主题对象发生变化时,会通知所有订阅者,使他们能够做出相应的处理。在 ZooKeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。ZooKeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些指定事件触发这个监听,那么就会想指定客户端发送一个事件通知来实现分布式的通知功能。

Watcher 具有以下特性

一次性

一旦一个 Watcher 被触发,ZooKeeper 都会将其从相应的存储中移除。因此,开发人员在
Watcher 的使用上要记住一点事需要反复注册。这样的设计有效的减轻了服务端的压力。

客户端串行执行

客户端 Watcher 回调过程是一个串行同步的过程,这为我们保证了顺序。所以千万不要为了一个 Watcher 的处理逻辑影响了这个客户端的 Watcher 回调。

轻量

Watcher 通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容,也就是说需要客户端主动重新去获取——这也是 ZooKeeper 的 Watcher 机制的一个非常重要的特性。如此轻量的 Watcher 机制设计,在网络开销和服务端内存开销上都是非常廉价的。

ACL

为了有效地保障节点数据的安全,避免误操作带来的数据随意变更而导致分布式系统出现异常,ZooKeeper 提供了一套完善的 ACL(Access Control List)权限控制机制来保障数据的安全。

ZooKeeper 提供了如下 5 中权限。

  • CREATD:创建子节点的权限
  • READ:获取节点数据和节点子列表的权限
  • WRITE:更新节点数据的权限
  • DELETE:删除子节点的权限
  • ADMIN:设置节点 ACL 的权限

需要注意的是,CREATE 和 DELETE 权限都是针对子节点列表的权限控制。

API 使用

Java 客户端 API 使用的例子都在我的 github

Curator

Curator 是 ZooKeeper 的一个开源客户端,不仅为开发者提供了更为便利的 API 接口,而且还提供了一些典型场景的使用参考,有如下几种

事件监听

通过原生的 API 来进行事件监听,不是很方便,需要开发人员反复注册 Watcher,比较繁琐。Curator 能够自动为开发人员处理反复注册监听,从而大大简化了原生 API 开发的繁琐过程。

Master 选举

在分布式系统中,经常会碰到这样的场景:对于一个复杂的任务,仅需要从集群中选举出一台进行处理即可。诸如此类的分布式问题,我们统称为“Master 选举”。借助 ZooKeeper,我们可以比较方便地实现 Master 选举的功能,大体思路为:选择一个根节点,例如 /master_select,多台机器同时向该节点创建一个节点 /master_select/lock,利用 ZooKeeper 的特性,最终只有一台机器能创建成功,成功的那台机器就作为 Master

分布式锁

分布式锁时控制分布式系统之间同步访问共享资源的一种方式。ZooKeeper 实现分布式锁的思路就是在指定的目下生成临时有序节点,序号最小的那个就获得锁。锁释放的时候,只要将该瞬时节点删除即可。这里需要注意“羊群效应”。

分布式计数器

ZooKeeper 实现分布式计数器的思路如下:指定一个数据节点作为计数器,多个应用实例在分布式锁的控制下,通过更新该数据节点的内容来实现技术功能。

有关上面场景的代码在我的 github 上。

参考

《从Paxos到Zookeeper:分布式一致性原理与实践》

标签:一文,ZooKeeper,Watcher,深入,客户端,数据,节点,分布式
来源: https://www.cnblogs.com/tailife/p/16364377.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有