经典分布式论文阅读:Zookeeper

本文是ZooKeeper论文的阅读笔记,ZooKeeper用于协调分布式系统中的进程,为分布式系统提供消息群发、共享寄存器、分布式锁这些中心化的服务。node

分布式系统中须要的协调服务包括:配置、组成员关系、领导选举和锁服务。ZooKeeper并无直接提供这些服务,由于更强的原语能够用来实现较弱的原语,ZooKeeper提供了API供开发者实现本身的原语。ZooKeeper的API操做相似文件系统的层级结构上的免等待数据对象,同时保证全部操做的客户端先进先出串行写入。ZooKpeer使用管道架构实现高吞吐和低延迟,更新操做采用Zab保证线性,读取操做在服务器本地进行,不须要肯定顺序。观察机制在数据更新以后通知客户端,使得客户端可以快速获取最新数据。数据库

ZooKeeper服务

ZooKeeper以库的形式向客户端提供API,库也负责客户端到ZooKeeper服务器的链接。ZooKeeper中的数据节点称为znode,以树型命名空间组织。客户端链接服务器后创建会话,经过会话句柄发送请求。bash

服务总览

ZooKeeper给客户端提供了数据对象的抽象(znode)。服务器

znode有两种类型:架构

  • 常规:数据对象正常建立和删除。
  • 临时:建立对象的会话终止以后,对象会被删除。

若是在建立文件的时候设置SEQUENTIAL标志,那么会在文件名后增长一个自动增长的计数器。ZooKeeper实现了观测(watch)机制,可以在数据对象更新后通知客户端,观测只会触发一次。分布式

数据模型:ZooKeeper中的数据模型是只支持全量读写的文件系统,znode保存应用程序的抽象概念,用来存储配置、元数据等信息。ui

会话:客户端链接ZooKeeper后创建会话,会话用来标识客户端。spa

客户端API

  • 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保证

ZooKeeper有两项基本的顺序保证日志

  • 线性写入:全部改变ZooKeeper状态的更新都是串行的;
  • 客户端先进先出:全部来自客户端的请求按照先进先出顺序执行。

能够举个例子演示这两个保证如何保障系统运行。假设一个系统选举主节点管理其余节点,主节点随后须要更新一些配置,而后通知其余节点,要求:

  • 主节点在修改配置过程,不但愿其余节点访问正在被修改的配置
  • 主节点在更新完成前崩溃,不但愿其余节点访问这些破碎的配置

能够设置一个readyznode解决,主节点能够在配置前删除,完成后从新创建。当其余节点看到ready不存在时就不读取配置。

可是还会存在问题:若是其余节点看到ready后读取配置,可是主节点随即删除开始修改配置,那么其余节点将获得过期的配置。这个问题能够采用观测机制来解决,ready删除后会及时通知其余节点。

ZooKeeper两个耐久性保证:

  • 若是大部分服务器都活跃,那么服务就是可用的
  • 若是ZooKeeper成功响应了一个修改请求,只要大部分的节点均可以最终恢复,那么修改就能够在无数次故障中保持持久。

原语例子

  • 配置管理:只须要将配置保存在一个znode中,各个进程能够经过观测来获取配置更新通知。
  • 会合:不少分布式系统包含主节点和工做节点,可是节点的调度由调度器决定,能够将主节点信息放在一个znode,供工做节点找到主节点。
  • 组成员关系:组成员进程上线以后能够在组对应的znode之下建立对应的临时子znode,成员进程退出以后临时znode也被删除,所以能够经过组znode的子znode获取组成员状态。
  • 简单锁:锁能够建立一个对应的znode实现。若是建立成功,那么获取锁。若是已经存在,那么须要等待锁被释放(znode被删除)后才能获取锁(建立znode)。
  • 无羊群效应的简单锁:简单锁会出现大量进程竞争的状况,能够将锁请求排序后,按次序分配锁。
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
复制代码
  • 双栅栏:双栅栏用来保证多个客户端的计算同时开始和同时结束。客户端开始计算以前添加znode到栅栏对应的znode之下,结束计算以后删除znode。客户端须要等待栅栏znode的子znode数量到达必定阈值后才能开始计算,客户端能够等待一个特殊的ready的znode的建立,当数量到达阈值后建立。客户端退出的时候须要等待子znode所有被删除,一样能够经过删除ready删除。

ZooKeeper应用

  • 解析服务:在雅虎的爬虫系统的解析服务中,主节点须要告知解析节点系统配置,解析节点须要报告本身的状态。所以,解析服务使用ZooKeeper管理配置领导选举。下图是系统读写操做状况,能够发现读取操做占大头。

  • Katta:Katta是一个分布式索引,主节点将分片分配给从节点并追踪进度,主要使用ZooKeeper进行组成员关系管理领导选举配置管理
  • 雅虎消息中介:雅虎消息中介负责无数话题下的消息的发布和接收,这些话题分布在多个服务器上,每一个服务器采用主从备份。系统的znode结构以下图所示,相似于shutdownmigration_prohibited是系统的配置信息,nodes保存了属于组成员的服务器信息,而topics保存了负责具体话题对应的主服务器已经从服务器,另外在主节点奔溃后须要领导选举

ZooKeeper实现

ZooKeeper的组件以下图所示,ZooKeeper的数据副本保存在每个服务器上,写操做须要经过一致性协议提交到数据库,而读取请求能够直接访问服务器本地数据库得到。ZooKeeper在应用修改到数据库以前会写入到磁盘,故障后采用快照加日志的方式进行故障。根据一致协议,写入请求会转发到领导(leader)节点。

请求处理器

请求处理器收到写入请求以后,会将其转换为幂等的事务,根据请求内容计算出新的数据、版本号和时间戳,等待应用到数据库中。

原子广播

ZooKeeper使用Zab做为原子广播协议,使用简单的多数认同达成一致性。Zab保证广播发送和接受的顺序是一致的,领导节点广播以前须要确保已经收到了前一个领导的广播。

多副本数据库

当服务器故障后,使用周期性的快照和快照以后的日志恢复。建立快照的时候并不须要锁定,由于事务都是幂等的,所以再次应用已经应用的修改没有影响。

客户端-服务器交互

当服务器执行一个写入操做后,会通知观测的客户端并清除观测,每一个服务器只负责通知本身链接的客户端。每一个读取请求对应着一个zxid,对应服务器上看到的最后一个写入事务的ID。由于读取是在服务器本地进行,可能在读取以前的一些写入没有同步到客户端链接的服务器,ZooKeeper提供了sync操做,保证sync以后的读取操做都可以得到发生在sync以前的写入结果。客户端会从服务器获取最新zxidzxid另一个做用就是保证客户端在切换服务器后,新服务器看到视图不能比客户端以前看到的视图落后,也就是服务器zxid不能早于客户端的zxid。若是检测客户端故障,会话是有超时时间的,客户端在没有活动期间也要发送心跳避免超时。

参考文献

  1. Hunt, Patrick, et al. "ZooKeeper: Wait-free Coordination for Internet-scale Systems." USENIX annual technical conference. Vol. 8. No. 9. 2010.
相关文章
相关标签/搜索