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 objects:zookeeper 可执⾏⼀个 client 的请求,⽆需等待别的 client 采取什么⾏动
watch mechanism:通过 watch 机制,client 不需轮询就可以接收到某 znode 更新的通知 。watch 表明发⽣了更改,但不提供更改的内容
linearizable writes:来⾃所有 client 的所有写操作都是可线性化的
FIFO client order:zookeeper 对于⼀个 client 的请求,严格按照该 client 发送请求的顺序执⾏
总得来说,Zookeeper主要完成以下三个贡献:
协调核⼼:提出了⼀种wait-free协调服务,具有宽松的⼀致性保证,可⽤于分布式系统。特别是,这描述了协调核⼼的设计和实现,且已经在许多关键应⽤中使⽤它们来实现各种协调技术。
协调⽅法:展⽰了如何使⽤Zookeeper来构建更⾼级别的协调原语,甚⾄是分布式应⽤程序中经常使⽤的阻塞和强⼀致的原语。
协调经验:⼀些使⽤Zookeeper并评估其性能的⽅法。
第⼆部分:Zookeeper服务
Zookeeper数据模型
Repblicated Database 是⼀个内存数据库,存储着⼀个层次性的⽂件系统,即⼀个数据树,每⼀个节点称为 znode 。
znode 并不⽤于通⽤数据存储,⽽是⽤来存储 client 引⽤的数据( ⽤于协调的元数据 )。⼀个 client 可以通过 API 来操纵 znode ,如上图中 app1 实现了⼀个简单的组成员⾝份协议:每个 client 进程 pi 在 /app1 下创建了⼀个 znode pi ,只要该进程正在运⾏,该节点便会持续存在 。
znode 还将元数据与 timestamp 和 version counter 关联,这使 client 可以跟踪对 znode 的更改并根据 znode 的版本执⾏条件更新 。
client 可以创建三种 znode:
Regular:client 显式地操纵和删除 regular znodes
Ephemeral:这种节点可以被显式地删除,也可以在创建这个节点的 session 断开时⾃动删除。该节点不能拥有⼦节点
Sequential:client 创建 znode 时设置 sequential flag ,该节点名字后会添加⼀个单调递增的序号
Zookeeper会话
当⼀个⽤户连接到Zookeeper时就会初始化⼀个会话。会话都有关联的超时限制。⽤户主动断开session连接或Zookeeper检测到⽤户出错都会结束⼀个会话。
当会话存在时,⽤户可以不断观测到不同⽤户操作带来状态改变,会话也是保证⽤户在以Zookeeper实例中的不同服务器间转换的基本单位。
客户端API
create(path, data, flags) :根据路径名和存储的数据创建⼀个 znode ,flags 指定 znode 类型
delete(path, version):版本号匹配情况下删除 path 下的 znode
exists(path,watch):如果 path 下 znode 存在,返回 true;否则返回 false 。watch 标志可以使 client
在 znode 上设置 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
session如何设置和读取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连接。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。