初识 ZooKeeper

284 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第28天,点击查看活动详情

ZooKeeper 是什么?

ZooKeeper 是一种用于分布式应用程序的分布式开源协调服务。分布式的应用程序可以基于 ZooKeeper 的基础能力来实现更顶层的服务间的同步、配置维护以及分组和命名服务。Zookeeper 被设计为易于编程,使用我们所熟悉的文件系统目录树结构作为数据模型。Zookeeper 运行在 Java 环境中,并且主要由 Java 和 C 编写。

众所周知,协调服务因特别容易出现争用条件和死锁等错误所以很难保证协调的正确性。而 ZooKeeper 设计的初衷是减轻分布式应用程序从头开始实现协调服务。

ZooKeeper 设计的目标

ZooKeeper 是设计简单

ZooKeeper 允许分布式进程通过共享分层级的 namespace 实现服务协调,该 namespace组织结构类似于标准文件系统。namespace 在 ZooKeeper 的术语叫 znodes,由数据寄存器组成,类似于文件和目录。与专为存储而设计的典型文件系统不同,ZooKeeper 数据保存在内存中,这意味着 ZooKeeper 可以实现高吞吐量和低延迟。

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

ZooKeeper 是多副本的

ZooKeeper 是多副本选举制的。组成 ZooKeeper 服务的节点是相互了解的,它们维护状态的内存中映像,以及持久存储中的事务日志和快照。只要大多数节点可用,ZooKeeper服务就会可用。

客户端连接到单个 ZooKeeper 服务器。客户端维护一个 TCP 连接,通过该连接发送请求、获取响应、获取监视事件和发送检测信号。如果与服务器的 TCP 连接中断,客户端将连接到其他服务器。

zkservice.jpeg

ZooKeeper 是严格顺序保证的

ZooKeeper 在每次更新时都会用一个数字标记,该数字反映了所有 ZooKeeper 事务的顺序。

ZooKeeper 是高性能的

ZooKeeper 的应用程序在数千台机器上运行,在读取比写入更常见的场景下,它的性能最佳,读取:写入的比率约 10:1。

ZooKeeper 的数据模型和分层级的命名空间

ZooKeeper 提供的命名空间很像标准文件系统。名称是由斜杠 (/) 分隔的路径元素序列。ZooKeeper命名空间中的每个节点都由路径标识。

分层级的命名空间

zknamespace.jpeg

节点

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

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

存储在命名空间中每个 znode 上的数据以原子方式读取和写入。读取获取与 znode 关联的所有数据字节,写入将替换所有数据。每个节点都有一个访问控制列表 (ACL),用于限制谁可以执行哪些操作。

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

条件更新和监视

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