本文是ZooKeeper论文的阅读笔记,ZooKeeper用于协调分布式系统中的进程,为分布式系统提供消息群发、共享寄存器、分布式锁这些中心化的服务。node
分布式系统中须要的协调服务包括:配置、组成员关系、领导选举和锁服务。ZooKeeper并无直接提供这些服务,由于更强的原语能够用来实现较弱的原语,ZooKeeper提供了API供开发者实现本身的原语。ZooKeeper的API操做相似文件系统的层级结构上的免等待数据对象,同时保证全部操做的客户端先进先出和串行写入。ZooKpeer使用管道架构实现高吞吐和低延迟,更新操做采用Zab保证线性,读取操做在服务器本地进行,不须要肯定顺序。观察机制在数据更新以后通知客户端,使得客户端可以快速获取最新数据。数据库
ZooKeeper以库的形式向客户端提供API,库也负责客户端到ZooKeeper服务器的链接。ZooKeeper中的数据节点称为znode,以树型命名空间组织。客户端链接服务器后创建会话,经过会话句柄发送请求。bash
ZooKeeper给客户端提供了数据对象的抽象(znode)。服务器
znode有两种类型:架构
若是在建立文件的时候设置SEQUENTIAL
标志,那么会在文件名后增长一个自动增长的计数器。ZooKeeper实现了观测(watch)机制,可以在数据对象更新后通知客户端,观测只会触发一次。分布式
数据模型:ZooKeeper中的数据模型是只支持全量读写的文件系统,znode保存应用程序的抽象概念,用来存储配置、元数据等信息。ui
会话:客户端链接ZooKeeper后创建会话,会话用来标识客户端。spa
create(path, data, flags)
:建立一个路径为path
的znode,将data[]
保存到其中,返回新znode的名称,flags
用来设置znode类型:普通或者临时,以及设置SEQUENTIAL
标志。delete(path, version)
:若是版本匹配,删除path
对应的znode。exists(path, watch)
:若是path
对应的znode存在,那么返回真,不然返回假。watch
标志让客户端观测这个znode。getData(path, watch)
:返回znode对应的数据和元数据,watch
功能相似。setData(path, data, version)
:若是版本匹配,将data[]
写入到path
对应的znode中。getChildren(path, watch)
:返回znode的子节点集合。sync(path)
:等待目前全部未决的更新,path
没什么用。以上所有的方法提供了阻塞版本和非阻塞版本,若是传入版本号为-1,那么不进行版本检查。.net
ZooKeeper有两项基本的顺序保证日志
能够举个例子演示这两个保证如何保障系统运行。假设一个系统选举主节点管理其余节点,主节点随后须要更新一些配置,而后通知其余节点,要求:
能够设置一个ready
znode解决,主节点能够在配置前删除,完成后从新创建。当其余节点看到ready
不存在时就不读取配置。
可是还会存在问题:若是其余节点看到ready
后读取配置,可是主节点随即删除开始修改配置,那么其余节点将获得过期的配置。这个问题能够采用观测机制来解决,ready
删除后会及时通知其余节点。
ZooKeeper两个耐久性保证:
Lock
1 n = create(l + “/lock-”, EPHEMERAL|SEQUENTIAL)
2 C = getChildren(l, false)
3 if n is lowest znode in C, exit
4 p = znode in C ordered just before n
5 if exists(p, true) wait for watch event
6 goto 2
复制代码
Unlock
1 delete(n)
复制代码
Write Lock
1 n = create(l + “/write-”, EPHEMERAL|SEQUENTIAL)
2 C = getChildren(l, false)
3 if n is lowest znode in C, exit
4 p = znode in C ordered just before n
5 if exists(p, true) wait for event
6 goto 2
复制代码
读锁之间能够互相兼容,和写锁互斥。
Read Lock
1 n = create(l + “/read-”, EPHEMERAL|SEQUENTIAL)
2 C = getChildren(l, false)
3 if no write znodes lower than n in C, exit
4 p = write znode in C ordered just before n
5 if exists(p, true) wait for event
6 goto 3
复制代码
ready
的znode的建立,当数量到达阈值后建立。客户端退出的时候须要等待子znode所有被删除,一样能够经过删除ready
删除。shutdown
、migration_prohibited
是系统的配置信息,nodes
保存了属于组成员的服务器信息,而topics
保存了负责具体话题对应的主服务器已经从服务器,另外在主节点奔溃后须要领导选举。ZooKeeper的组件以下图所示,ZooKeeper的数据副本保存在每个服务器上,写操做须要经过一致性协议提交到数据库,而读取请求能够直接访问服务器本地数据库得到。ZooKeeper在应用修改到数据库以前会写入到磁盘,故障后采用快照加日志的方式进行故障。根据一致协议,写入请求会转发到领导(leader)节点。
请求处理器收到写入请求以后,会将其转换为幂等的事务,根据请求内容计算出新的数据、版本号和时间戳,等待应用到数据库中。
ZooKeeper使用Zab做为原子广播协议,使用简单的多数认同达成一致性。Zab保证广播发送和接受的顺序是一致的,领导节点广播以前须要确保已经收到了前一个领导的广播。
当服务器故障后,使用周期性的快照和快照以后的日志恢复。建立快照的时候并不须要锁定,由于事务都是幂等的,所以再次应用已经应用的修改没有影响。
当服务器执行一个写入操做后,会通知观测的客户端并清除观测,每一个服务器只负责通知本身链接的客户端。每一个读取请求对应着一个zxid
,对应服务器上看到的最后一个写入事务的ID。由于读取是在服务器本地进行,可能在读取以前的一些写入没有同步到客户端链接的服务器,ZooKeeper提供了sync
操做,保证sync
以后的读取操做都可以得到发生在sync
以前的写入结果。客户端会从服务器获取最新zxid
,zxid
另一个做用就是保证客户端在切换服务器后,新服务器看到视图不能比客户端以前看到的视图落后,也就是服务器zxid
不能早于客户端的zxid
。若是检测客户端故障,会话是有超时时间的,客户端在没有活动期间也要发送心跳避免超时。