分布式协调服务
ZooKeeper是一款开源的分布式应用
的分布式协调服务
。它包含一个简单的原语集
,分布式应用程序能够基于它实现同步服务,配置维护和命名服务等。Zookeeper 设计很容易进行编程,它使用一种相似于文件系统的目录树结构的数据模型,以 java 方式运行,有 java 和 c 的绑定(binding)。html
协调服务
是很是难以被正确实现的。他们特别容易产生诸如竞态条件、死锁等错误。ZooKeeper背后的动机是为分布式应用程序减轻从零开始实现协调服务的难度。java
ZooKeeper容许分布式进程经过与标准文件系统相似组织的共享层级命名空间来相互协调。命名空间被称为znode
的数据记录组成,用ZooKeeper的说法,这些记录和标准文件系统中的文件和目录很是类似。与典型的用于存储的文件系统不一样,ZooKeeper数据保存在内存中,这意味着ZooKeeper能够实现高吞吐量和低延迟。node
Zookeeper的实现着重于高性能、高可用性和严格的顺序访问。ZooKeeper的性能方面意味着它能够用于大型分布式系统。可靠性方面使它不会形成单点故障。严格的排序意味着能够在客户端实现复杂的同步原语。算法
就像它协调的分布式进程同样,Zookeeper 自身也在被称为“ensemble”的一组主机之间进行复制。 数据库
客户端(client)链接到任意一台ZooKeeper服务器。客户端维护一个TCP链接,经过它发送请求、获取响应、获取监视事件以及发送心跳。若是到服务器的TCP链接中断,客户端将链接到其余不一样的服务器。apache
ZooKeeper使用反映全部ZooKeeper事务顺序的数字来标记每一个更新。后续操做可使用该次序来实现更高级别的抽象,例如同步原语。编程
在应对以“读”为主的负载时尤为地快速。ZooKeeper应用程序在数千台机器上运行,而且在读取比写入更为广泛的状况下,性能表现最佳,比例约为10:1。缓存
ZooKeeper提供的命名空间与标准文件系统很是类似。路径是由斜杠/
分隔的一系列元素。 ZooKeeper命名空间中的每一个节点都由一个路径标识。 服务器
默认节点
和临时节点
与标准文件系统不一样的是,ZooKeeper命名空间中的每一个节点均可以拥有与其相关的数据以及子节点。这就像一个文件系统中能够存在一个文件或一个目录。ZooKeeper被设计用来存储相关的协调数据,如状态信息、配置、位置信息等等,因此每一个节点上存储的数据一般都很小,在字节(byte)到千字节(kb)范围内。咱们使用术语znode来清楚地说明咱们正在讨论ZooKeeper数据节点。分布式
Znode 维护了一个状态(stat
)结构,其中包含了表示数据改变、访问控制列表(ACL)改变的版本号、时间戳,可用于缓存校验、协调更新。每当一个znode的数据发生变化,版本号就会增长。例如,每当客户端检索数据时,客户端也会接收到相应数据的版本信息。
存储在命名空间中每一个节点上的数据是以原子方式读取和写入的。读取一个znode将得到其所有的数据,而写入则替换其所有的数据。
ZooKeeper也有临时节点的概念。当建立临时节点的客户端会话一直保持活动,瞬时节点就一直存在。而当会话终结时,瞬时节点被删除。
条件更新
和监视
(watches)ZooKeeper 支持“监视”(watches)的概念。客户端能够在znode上设置一个监视(watch)。当 znode改变时,监视(watch)将被触发并移除。当监视(watch)被触发时,当“监视”被触发时,客户端会收到一个描述了 znode 的变动的数据包。若是客户端和Zookeeper服务器之间的链接断开时,客户端将会收到一个本地通知。
保证
(Guarantees)Zookeeper很是地快速也很是简单。不过,因为它的目标是做为构建诸如“同步”这类更复杂服务的基础,它提供了一些的一组保证:
ZooKeeper的一个设计目标是提供一个很是简单的编程接口。 所以,它只支持这些操做:
在(命名空间)树的一个特定地址上建立一个节点。
删除一个节点。
判断某个路径下是否存在该节点。
获取节点的数据。
向节点写入数据。
检索节点的子节点列表。
等待数据传播完成。
实现原理
ZooKeeper Components 显示了ZooKeeper服务的高级组件。除Request Processor
外,构成ZooKeeper服务的每一个服务器都复制每一个组件的副本。
replicated database
是一个内存数据库,它包含了整颗数据树。数据写入在应用到内存数据库以前,会先序列化到磁盘。
每个 Zookeeper 服务器都向客户端提供服务,客户端链接到一个确切的Zookeeper服务器提交请求。读请求从服务器数据库的本地拷贝中获取。改变Zookeeper服务状态的请求、写入请求经过一个一致性协议进行处理。
做为协议的一部分,客户端的全部写入请求都被转发到一个单独的服务器,该服务器被称为 leader。而其他的服务器,被称为follower,从leader接收消息提案(proposal)并对消息的交付取得一致。消息层维护leader失效时的更新替换以及leader和follower之间的同步。
Zookeeper 使用自定义的原子消息协议。因为消息层是原子的,Zookeeper能够保证本地的复制品不会不一致。当 leader收到一个写入请求时,它计算系统所处的状态以及什么时候应用写入请求,并将此转换为一个事务,包含新的状态。
Zookeeper 的编程接口特地地定义得很简单。然而,经过这些编程接口能够更高阶的操做,例如同步原语,成员分组,全部权,等等。
Zookeeper 被设计为高性能。但实际是否如此呢?在雅虎研发中心的 Zookeeper 开发团队的研究结果代表的确如此。(参见下图:Zookeeper 吞吐量随读写比的变化)。在“读”多于“写”的应用程序中尤为地高性能,由于“写”会致使在全部的服务器间同步状态。(“读”多于“写”是协调服务的典型场景。)
Zookeeper 吞吐量随读写比的变化
注:3.2版本的读/写性能相对于3.1版本之前有最多达2倍的提高。
基准测试也代表了 Zookeeper 的可靠性。图“错误发生的状况下的可靠性”展现了 Zookeeper 是如何应对各类不一样的失效的。图中标注的事件以下:
一个 Follower 失效而后恢复。
另外一个不一样的 Follower 失效而后恢复。
Leader 失效。
两个 Follower 失效而后恢复。
另外一个 Leader 失效。
Zookeeper 已经被成功地用在许多工业级的应用。在雅虎,Zookeeper被用做雅虎消息中间件的协调和失效恢复服务,该系统是一个高伸缩性的发布订阅系统,管理着成千上万的主题复制和数据分发。Zookeeper还被用在雅虎爬虫的抓取服务上,用于管理失效恢复。许多雅虎的广告系统也用 Zookeeper 实现可靠的服务。