ZooKeeper是一种针对分布式应用程序的高性能协调服务。它在一个简单的接口中公开了常见的服务——例如命名、配置管理、同步和组服务——因此您不必从头开始编写它们。您可以使用它来实现共识、组管理、领导人选举和到场协议。你可以在此基础上为你自己的特定需求而建。
ZooKeeper
是一个开源的分布式应用程序协调服务。它公开了一组简单的原语,分布式应用程序可以在这些原语的基础上实现更高级别的服务,用于同步、配置维护、组和命名。它被设计为易于编程,并使用了一个数据模型,其风格类似于文件系统的目录树结构。它运行在Java中,并具有Java和C的绑定
。
众所周知,协调服务很难做好。它们特别容易出现竞争条件和死锁等错误。ZooKeeper
背后的动机是减轻分布式应用程序从零开始实现协调服务的责任。
ZooKeeper is simple. ZooKeeper允许分布式进程通过与标准文件系统组织类似的共享层次命名空间相互协调。名称空间由数据寄存器(用ZooKeeper
的话说,称为znodes
)组成,这些寄存器类似于文件和目录。与设计用于存储的典型文件系统不同,ZooKeeper
数据保存在内存中,这意味着ZooKeeper
可以实现高吞吐量和低延迟数。
ZooKeeper实现非常重视高性能、高可用性和严格有序的访问。ZooKeeper
的性能方面意味着它可以用于大型分布式系统。可靠性方面使其不会成为单点故障。严格的顺序意味着可以在客户机上实现复杂的同步原语。
ZooKeeper is replicated. 和它所协调的分布式进程一样,ZooKeeper
本身也打算在一组称为合集的主机上进行复制。
组成ZooKeeper
服务的服务器必须相互了解。它们在持久存储中维护状态的内存映像以及事务日志和快照。只要大多数服务器可用,ZooKeeper
服务就可用。
客户机连接到单个ZooKeeper服务器。客户机维护一个TCP
连接,通过它发送请求、获取响应、获取监视事件和发送心跳。如果到服务器的TCP
连接中断,客户机将连接到另一台服务器。
ZooKeeper is ordered. ZooKeeper给每个更新贴上一个数字,这个数字反映了所有ZooKeeper事务的顺序。后续操作可以使用该顺序实现更高级别的抽象,比如同步原语。
ZooKeeper is fast. 在“以读取为主”的工作负载中,它尤其快。ZooKeeper
应用程序运行在数千台机器上,当读操作比写操作更常见时,它的性能最好,比率约为10:1
。
ZooKeeper
提供的名称空间非常类似于标准文件系统。名称是由斜杠(/)
分隔的路径元素序列。ZooKeeper
名称空间中的每个节点都由一个路径标识。
ZooKeeper
的层次名称空间:
与标准文件系统不同,ZooKeeper
名称空间中的每个节点都可以拥有与其关联的数据和子节点。这就像一个文件系统允许一个文件同时也是一个目录。(ZooKeeper
的设计目的是存储协调数据:状态信息、配置、位置信息等,因此在每个节点上存储的数据通常很小,以字节到千字节为单位)。我们使用术语znode
来表明我们在讨论ZooKeeper
数据节点。
Znodes
维护一个stat结构
,其中包含数据更改
、ACL更改
和时间戳的版本号
,以允许缓存验证
和协调更新
。每次znode
的数据发生变化,版本号就会增加。例如,每当客户机检索数据时,它也接收数据的版本。
存储在名称空间中的每个znode
中的数据是原子式读写的。读取获取与znode
关联的所有数据字节,而写入则替换所有数据。每个节点都有一个访问控制列表(ACL)
,用于限制谁可以做什么。
ZooKeeper
也有临时节点
的概念。只要创建znode
的会话处于活动状态
,这些znode
就会存在。当会话结束时,删除znode。当您想要实现[tbd]
时,临时节点非常有用。
ZooKeeper
支持手表的概念。Client可以在znode
上设置手表。当znode
发生更改时,将触发并删除一个手表。当一个手表被触发时,客户端收到一个数据包,说znode
已经更改。如果客户机和ZooKeeper服务器之间的连接断开,客户机将收到一个本地通知。这些可以用来[tbd]
。
ZooKeeper
是非常快,非常简单。但是,由于它的目标是作为构建更复杂服务(比如同步)的基础,所以它提供了一组担保。这些都是:
ZooKeeper的设计目标之一是提供一个非常简单的编程接口。因此,它只支持以下操作:
ZooKeeper Components 显示ZooKeeper服务的高级组件。除了请求处理器之外,构成ZooKeeper服务的每个服务器都复制自己的每个组件副本。
The replicated database是一个包含整个数据树的内存数据库。更新将被记录到磁盘以获得可恢复性,写操作在应用到内存数据库之前被序列化到磁盘。
每个ZooKeeper服务器都为客户端提供服务。客户机仅连接到一个服务器来提交请求。读取请求由每个服务器数据库的本地副本提供服务。更改服务状态的请求(写请求)由an agreement protocol处理。
作为the agreement protocol的一部分,所有来自客户端的写请求都被转发到一个名为leader的服务器上。其他的ZooKeeper服务器(称为追随者)接收来自领导者的消息建议,并就消息传递达成一致。消息层负责在失败时替换领导者,并将追随者与领导者同步。
ZooKeeper使用自定义原子消息传递协议。因为消息层是原子的,所以ZooKeeper可以保证本地副本不会发散。当leader接收到写请求时,它会计算要应用写时系统的状态,并将其转换为捕获这个新状态的事务。
ZooKeeper的编程接口非常简单。然而,使用它,您可以实现更高阶的操作,例如同步原语、组成员关系、所有权等。一些分布式应用程序使用它来:[tbd: add uses from white paper and video presentation.]
详情请参阅[tbd]
ZooKeeper被设计成高性能.但真的是这样吗?Yahoo!的ZooKeeper开发团队的研究结果。研究表明确实如此。(See ZooKeeper Throughput as the Read-Write Ratio Varies.)在读多于写的应用程序中,它的性能尤其高,因为写涉及同步所有服务器的状态。(读编号超过写通常是协调服务的情况。)
ZooKeeper的吞吐量随着读写比的变化而变化,这是一个ZooKeeper 3.2版本的吞吐量曲线图,运行在两台2Ghz Xeon和两台SATA 15K RPM驱动器的服务器上。其中一个驱动器用作专用的管理员日志设备。快照被写入操作系统驱动器。写请求为1K写,读请求为1K读。“服务器”表示ZooKeeper集合的大小,即组成服务的服务器数量。大约有30台其他服务器用于模拟客户机。ZooKeeper集合的配置是这样的:leaders不允许从客户端连接。
Note:在3.2 r/w版本中,性能比前一个3.1版本提高了约2倍。
基准测试也表明它是可靠的。错误存在时的可靠性显示了部署如何响应各种故障。图中标注的事件如下:
为了显示系统在注入故障时随时间的行为,我们运行了一个由7台机器组成的ZooKeeper服务。我们运行了与以前相同的饱和度基准测试,但这次我们将写百分比保持在30%不变,这是预期工作负载的保守比例。
从这张图中有几个重要的观察结果。首先,如果跟随者失败并迅速恢复,那么即使失败了,ZooKeeper仍然能够维持高吞吐量。但也许更重要的是,leader election算法允许系统恢复得足够快,以防止吞吐量大幅下降。在我们的观察中,ZooKeeper用了不到200毫秒的时间选出一个新的领导者。第三,随着跟随者的恢复,一旦他们开始处理请求,ZooKeeper就能够再次提高吞吐量。
ZooKeeper已成功应用于许多工业领域。Yahoo!作为雅虎的协调和故障恢复服务!Message Broker是一个高度可伸缩的发布-订阅系统,管理用于复制和数据交付的数千个主题。它被Yahoo!爬虫程序,它还管理故障恢复。一些雅虎!广告系统也使用ZooKeeper来实现可靠的服务。
鼓励所有用户和开发人员加入社区并贡献他们的专业知识。有关更多信息,请参见Apache上的Zookeeper项目。