Apache > ZooKeeper
 

ZooKeeper

ZooKeeper:分布式应用程序的分布式协调服务

ZooKeeper 是一种分布式、开源协调服务,适用于分布式应用程序。它公开了一组简单的基元,分布式应用程序可以在其基础上构建用于同步、配置维护、组和命名的更高级别服务。它设计为易于编程,并使用类似于文件系统熟悉的目录树结构的数据模型。它在 Java 中运行,并具有 Java 和 C 的绑定。

协调服务出了名的难以正确获得。它们特别容易出现竞争条件和死锁等错误。ZooKeeper 背后的动机是减轻分布式应用程序从头开始实现协调服务的责任。

设计目标

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

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

ZooKeeper 已复制。 与它协调的分布式进程一样,ZooKeeper 本身旨在复制到一组称为集合的主机上。

ZooKeeper Service

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

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

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

ZooKeeper 很快。它在“读为主”的工作负载中尤其快。ZooKeeper 应用程序在数千台机器上运行,并且在读取比写入更常见的情况下性能最佳,比例约为 10:1。

数据模型和分层命名空间

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

ZooKeeper 的分层命名空间

ZooKeeper's Hierarchical Namespace

节点和临时节点

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

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

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

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

条件更新和监视

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

3.6.0 中的新增功能:客户端还可以对 znode 设置永久性递归监视,这些监视在触发后不会被移除,并且会触发对已注册 znode 及其所有子 znode 的递归更改。

保证

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

简单 API

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

实现

ZooKeeper 组件显示了 ZooKeeper 服务的高级组件。除了请求处理器外,组成 ZooKeeper 服务的每台服务器都会复制其自己每个组件的副本。

ZooKeeper Components

复制的数据库是一个包含整个数据树的内存数据库。更新记录到磁盘以进行恢复,并且在应用到内存数据库之前将写入序列化到磁盘。

每个 ZooKeeper 服务器都为客户端提供服务。客户端连接到恰好一个服务器以提交请求。读取请求由每个服务器数据库的本地副本提供服务。更改服务状态的请求(写入请求)由协议协议处理。

作为协议协议的一部分,来自客户端的所有写入请求都转发到一个称为领导者的服务器。其余的 ZooKeeper 服务器(称为跟随者)从领导者那里接收消息提议并就消息传递达成一致。消息传递层负责在发生故障时替换领导者,并将跟随者与领导者同步。

ZooKeeper 使用自定义原子消息传递协议。由于消息传递层是原子的,因此 ZooKeeper 可以保证本地副本永远不会发散。当领导者收到写入请求时,它会计算写入应用时的系统状态,并将其转换为捕获此新状态的事务。

用途

ZooKeeper 的编程接口非常简单。但是,您可以使用它来实现更高阶的操作,例如同步原语、组成员资格、所有权等。

性能

ZooKeeper 被设计为高性能。但事实如此吗?雅虎研究部门的 ZooKeeper 开发团队的结果表明确实如此。(请参见 ZooKeeper 吞吐量随读写比率的变化。)在读多于写的应用程序中,它的性能尤其高,因为写涉及同步所有服务器的状态。(读多于写通常是协调服务的情况。)

ZooKeeper Throughput as the Read-Write Ratio Varies

ZooKeeper 吞吐量随读写比率的变化 是 ZooKeeper 版本 3.2 在具有双 2Ghz Xeon 和两个 SATA 15K RPM 驱动器的服务器上运行时的吞吐量图。一个驱动器用作专用的 ZooKeeper 日志设备。快照被写入到操作系统驱动器。写入请求是 1K 写入,读取请求是 1K 读取。“服务器”表示 ZooKeeper 集群的大小,即组成该服务服务器的数量。大约 30 台其他服务器用于模拟客户端。ZooKeeper 集群配置为领导者不允许来自客户端的连接。

注意

在 3.2 版本中,读/写性能比 以前的 3.1 版本 提高了约 2 倍。

基准测试还表明它也很可靠。在出现错误时提高可靠性 展示了部署如何应对各种故障。图中标记的事件如下

  1. 跟随者故障和恢复
  2. 其他跟随者故障和恢复
  3. 领导者故障
  4. 两个跟随者故障和恢复
  5. 另一个领导者故障

可靠性

为了展示随着故障注入系统行为随时间推移的变化,我们运行了一个由 7 台机器组成的 ZooKeeper 服务。我们运行了与之前相同的饱和基准,但这次我们将写入百分比保持在恒定的 30%,这是我们预期工作负载的保守比率。

Reliability in the Presence of Errors

从该图表中可以得出一些重要的观察结果。首先,如果跟随者快速故障并恢复,则 ZooKeeper 能够在故障情况下维持高吞吐量。但可能更重要的是,领导者选举算法允许系统足够快地恢复,以防止吞吐量大幅下降。根据我们的观察,ZooKeeper 花费不到 200 毫秒来选举新领导者。第三,随着跟随者恢复,ZooKeeper 能够在他们开始处理请求后再次提高吞吐量。

ZooKeeper 项目

ZooKeeper 已在许多工业应用中成功使用。Yahoo! 使用它作为 Yahoo! 消息代理的协调和故障恢复服务,这是一个管理数千个主题以进行复制和数据传递的高可扩展发布-订阅系统。Yahoo! 爬虫的获取服务使用它,它还管理故障恢复。许多 Yahoo! 广告系统也使用 ZooKeeper 来实现可靠的服务。

鼓励所有用户和开发人员加入社区并贡献他们的专业知识。有关更多信息,请参阅Apache 上的 Zookeeper 项目