zookeeper论文解读

Zookeeper论文解读

简介

Zookeeper是一种用于协调分布式应用程序过程的服务,其旨在提供一个简单而高性能的内核,用于在客户端提供复杂的协调原语(包括组消息、共享寄存器,分布式锁服务,集中式服务)。Zookeper提供的接口具有wait-free的共享寄存器,具有类似于分布式文件系统的缓存无效的事件驱动机制,以提供简单而强大的协调服务。基于wait-free的性质,Zookeeper对每一个客户端提供了关于文件读写执行的保证以及所有能够改变Zookeeper状态的请求的线性一致性的保证。

第一部分:综合介绍

1.1 协调方案

大型的分布式应用都需要不同形式的协调(coordination)方案(协调方案等同于保持一致性和可靠性的方式 ),举例来说,调整集群中某项参数的统一,对集群中分布式文件的读写请求的协调,分布式锁等等,都是不同形式的协调方案。通常来说,不同的分布式系统为了使得系统能够正确地协调,需要根据自身不同的服务内容进行不同的设计。例如亚马逊的排队服务就主要对如何解决分布式条件下的任务排队问题进行了详细地设计。为了实现master的选举,chubby在分布式锁服务的设计上提供了保证。

无论是哪种设计,分布式的服务系统都是通过对分布式原语详细而复杂的设计实现的。这样设计的好处是尽可能地让服务地主体都集中于服务端,让客户端仅需要简单的操作就可以获得想要的分布式服务,但是带来弊端是服务器端的高负载以及复杂的服务端设计。Zookeeper的原语设计并不遵循上述的设计理念,通过设计一个协调核以及暴露的API接口,帮助开发者开发自己需要的原语。

Zookeeper舍弃许多分布式系统中十分看重的阻塞原语(即锁),阻塞原语不仅实现复杂,而且使得整个系统效率低下。Zookeeper实现的API操作所谓的wait-free data objects,类似于chubby中所实现的API,但缺少了各种阻塞原语(open(),close())。除此之外,Zookeeper还提供关于操作顺序的保证,同时对用户所有文件读写的操作和线性写的顺序保证可以高效地实现服务。

Zookeeper使用管道结构允许用户存在未完成的读写请求,这样的管道结构使单一用户的按照FIFO client order的操作成为可能,对用户FIFO client order保证允许用户进行异步操作。

为了保证更新操作满足linearizable writes,Zookeeper使用了名为Zab的基于leader的原子广播协议。

缓存客户端的数据是提高读取性能的重要技术。例如,对于进程来说,缓存当前leader的标识符是有用的,而不是每次需要知道leader时都去进行探测。Zookeper使用观watch mechanism使客户端能够缓存数据,而无需直接管理客户端缓存。

  • wait-free data objectszookeeper 可执行一个 client 的请求,无需等待别的 client 采取什么行动
  • watch mechanism:通过 watch 机制,client 不需轮询就可以接收到某 znode 更新的通知 。watch 表明发生了更改,但不提供更改的内容
  • linearizable writes:来自所有 client 的所有写操作都是可线性化的
  • FIFO client orderzookeeper 对于一个 client 的请求,严格按照该 client 发送请求的顺序执行

总得来说,Zookeeper主要完成以下三个贡献:

  • 协调核心:提出了一种wait-free协调服务,具有宽松的一致性保证,可用于分布式系统。特别是,这描述了协调核心的设计和实现,且已经在许多关键应用中使用它们来实现各种协调技术。
  • 协调方法:展示了如何使用Zookeeper来构建更高级别的协调原语,甚至是分布式应用程序中经常使用的阻塞和强一致的原语。
  • 协调经验:一些使用Zookeeper并评估其性能的方法。

第二部分:Zookeeper服务

Zookeeper数据模型

在这里插入图片描述

Repblicated Database 是一个内存数据库,存储着一个层次性的文件系统,即一个数据树,每一个节点称为 znode

znode 并不用于通用数据存储,而是用来存储 client 引用的数据( 用于协调的元数据 )。一个 client 可以通过 API 来操纵 znode ,如上图中 app1 实现了一个简单的组成员身份协议:每个 client 进程 pi/app1 下创建了一个 znode pi ,只要该进程正在运行,该节点便会持续存在 。

znode 还将元数据与 timestampversion counter 关联,这使 client 可以跟踪对 znode 的更改并根据 znode 的版本执行条件更新 。

client 可以创建三种 znode

  • Regularclient 显式地操纵和删除 regular znodes
  • Ephemeral:这种节点可以被显式地删除,也可以在创建这个节点的 session 断开时自动删除。该节点不能拥有子节点
  • Sequentialclient 创建 znode 时设置 sequential flag ,该节点名字后会添加一个单调递增的序号

Zookeeper会话

当一个用户连接到Zookeeper时就会初始化一个会话。会话都有关联的超时限制。用户主动断开session连接或Zookeeper检测到用户出错都会结束一个会话。

当会话存在时,用户可以不断观测到不同用户操作带来状态改变,会话也是保证用户在以Zookeeper实例中的不同服务器间转换的基本单位。

客户端API

  • create(path, data, flags) :根据路径名和存储的数据创建一个 znodeflags 指定 znode 类型
  • delete(path, version):版本号匹配情况下删除 path 下的 znode
  • exists(path,watch):如果 pathznode 存在,返回 true;否则返回 falsewatch 标志可以使 clientznode 上设置 watch
  • getData(path, watch):返回 znode 的数据和对应的元数据,watch的作用个exists的一致
  • setData(path, data, version):版本匹配前提下,将 data 写入 znode
  • getChildren(path, watch):返回 path 对应 znode 的子节点集合
  • sync(path):等待 sync 之前的所有更新应用到 client 连接的服务器上

client 进行更新操作时,会携带上次获取到的 version 值发起请求,若请求的 version 号与 server 的不匹配,说明该数据已被别的 client 更新,则更新将失败 。

所有的方法在 API 中都有一个同步版本和一个异步版本 。当应用程序执行单个 zookeeper 操作且没有并发执行的任务时,使用同步 API ;异步 API 可以并行执行多个未完成的 zookeeper 操作 。

Zookeeper提供的保证

Linearizable writes:all requests that update the state of ZooKeeper are serializable and respect prece-dence;
FIFO client order: all requests from a given client areexecuted in the order that they were sent by the client.

Zookeeper中的线性化被称之为A-linearizability(异步线性化),允许客户有多个未完成的操作,且未完成的操作在管道中依然保持输入输出的顺序。

关于原语

参数管理

通过设置watch flag,观察对应的znode是否已经被修改

集结

如果用户启动了多个线程,而其中的主线程出现了错误而被done掉,那么其他线程可以通过watch主线程中的相关参数是否存在来决定是否需要结束自身。

组成员管理
简单的锁服务

简单锁服务的实现利用锁文件,由一个znode表示一个锁,如果一个用户能成功创建带有EPHEMERAL标志的锁,则代表其成功获取了锁。否则,该用户则对已有的锁文件设置watch标志,如果被提醒文件的销毁(即锁的释放),则再次重复创建操作。

不会造成畜群效应的简单锁服务
Lock
1 n = create(l +“/lock-”, EPHEMERAL|SEQUENTIAL)
2 C = getChildren(l, false)
3 ifn is lowest znode in C, exit
4 p = znode in C ordered just before n
5 ifexists(p, true) wait for watch event
6 goto 2

Unlock
1 delete(n)

相较于最简单的锁服务,为了不使集群出现畜群效应,做出了以下的修改

  1. 删除znode只会导致一个客户端醒来,因为每个znode都被另一个客户端监视,所以没有群体效应;

  2. 没有轮询或超时机制;

  3. 由于实施的方式,可以通过浏览数据来查看竞争锁的数量,断开锁和调试锁问题。

读写锁
Write Lock
1 n = create(l +“/write-”, EPHEMERAL|SEQUENTIAL)
2 C = getChildren(l, false)
3 ifn is lowest znode in C, exit
4 p = znode in C ordered just before n
5 ifexists(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 ifexists(p, true) wait for event
6 goto 3
Double Barrier

Double Barrier使用户能够同步进程计算的开始和结束。当进程的数目达到一定限制,将创建一个监控的文件b,并在其下创建属于自身进程的子文件,而当所有的进程都结束了计算并将子文件从b中删去后,所有的进程才可以算是计算结束。

第三部分 Zookeeper的应用

第四部分 ZooKeeper的架构实现

在这里插入图片描述

上图展示了一个Zookeeper服务的组成,每一个Zookeeper 服务器上都包含这三部分的组件。每当服务器收到一个请求,Request Processor将对执行这条请求做准备,如果这条请求需要协调其他服务器,服务器将使用Atomic Broadcast对需要协调的内容进行发协调,最终的请求完成将在所有服务器上完成,数据的修改将存入Replicated Database中。

每一个用户都连接到一个具体的Zookeeper服务器上,针对不同的请求类型:

  • reading request:在本地的服务器完成
  • writing request:则需要一个协议。

Request Processor

由于Zookeeper的服务器提供了异步的API,因此同一时刻不同服务器在服务时可能包含了许多未完成的异步事务。这些异步的事件都隐含了一个关于未来的版本号,这是在这些写请求交由leader处理时生成的,这些对于未来的事务的保证,当一个携带更新版本号的新的写请求发生时,leader需要比对这个版本号和已有的未来版本号,如果这两种版本号不相同或者发生了冲突,则代表了可能的事务冲突,因此服务器需要拒绝这些新的写请求。

Atomic Broadcast

Zookeeper使用Zab在整个集群中保证update请求命令顺序的统一,Zab使用quorum在整体中进行投票,当一个update请求在超过半数的server中得到应答,则这个update命令所改变的state就可以生效。当一个新的leader产生时,对所有未完成的请求都将从旧的leader上利用TCP传输到新的leader上,且所有的,命令会先进性日志预写,以防丢失。

Replicated Database

Replicated databases主要用于存储Zookeeper的状态。Replicated database中的数据总是Zookeeper的一个快照,因为在管道中或者日志中还有许多指令尚未执行或收到,因此在运行了一段时间后,Znode 都需要对收到的所有日志信息进行回放,已达到最新的快照。这一点在灾备恢复也有体现,在恢复到最新的状态,Znode需要获取一个较近的快照,并在此基础上回放日志信息。

用户-服务器端的交互

当用户发起一个写请求,由于写请求会改变Zookeeper的状态,写请求会被发送给leader进行处理,并被保证绝对的读写顺序,在这个请求被处理的过程中,其他的写请求不会并行执行。写请求的结果是同信息发送给所有的Znode并让其更新自身的Replicated database的,但是,由于请求可能是异步的,大多数信息可能仅存在于pipeline中,并未真实地更新了本地Replicated database地状态,因此,这对仅在本地进行处理地读请求来讲就会造成一些不一样地情况,如果直接在一个Znode上执行读请求,可能会获取到一个和其他Znode不一样地数据版本。如果在执行读请求是执行sync(),那么pipeline中的信息会被更新后再返回Zookeeper的状态。

于pipeline中,并未真实地更新了本地Replicated database地状态,因此,这对仅在本地进行处理地读请求来讲就会造成一些不一样地情况,如果直接在一个Znode上执行读请求,可能会获取到一个和其他Znode不一样地数据版本。如果在执行读请求是执行sync(),那么pipeline中的信息会被更新后再返回Zookeeper的状态。

以上的情况是时常发生的,问题在于当一个用户在一个Znode上连接了Session后,因为种种原因转移到其他Seesion上,例如原先的服务器出现了问题,那么就可能出现用户看到的数据状态是不一样的这种请求,如果状态一致,用户可以在新的服务器上继续自己的Seesion,否则,用户必须进行等待,等待该服务器的数据状态达到自己看到的数据状态,才能继续Session连接。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值