Zookeeper 进阶

zookeeper 是一个开放源代码的分布式协调服务,设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

分布式程序可以基于zookeeper 实现诸如 数据发布订阅,负载均衡,命名服务,分布式协调、通知,集群管理 Master选举,分布式锁,分布式队列等功能。

基本概念

集群角色:zookeeper 中,没有传统的主从概念,引入了leader,follower,observer 三种角色。zookeeper集群中所有机器通过一个leader 选举过程来选定一台被称为leader的机器,leader服务器为客户端提供读和写服务。除了leader外,还包括follower和observer,他们都能够提供服务,唯一的区别是observer 不参与leader选举过程,也不参与写操作的”过半写成功”策略,因此observer可以在不影响写性能的情况下提升集群的读性能。

会话(sesseion): session 指客户端会话。在zk中,一个客户端连接是指客户端和服务端之间的一个TCP长连接,客户端启动时,首先与服务器建立一个TCP连接,从第一次建立连接开始,客户端的生命周期就开始了。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向zk服务器发送请求并接受相应,同时还能够通过该连接接收来自服务器的watcher事件通知。

数据节点znode: zookeeper将所有数据存储在内存中,数据模型是一颗树,由斜杠分割的路径,就是一个Znode 每个Znode 都会保存自己的数据内容,同时还会保存一系列的属性信息。zk中,数据节点分为持久节点和临时节点两种,持久节点就是一旦创建,除非主动进行移除工作,否则znode会一直保存在zk上,而临时节点不一样,它的生命周期和客户端会话绑定,一旦客户端会话失败,那么这个客户端创建的临时节点也会被移除。

版本:对于每个znode,zk 都会为其维护一个叫stat的数据结构,stat 记录了这个Znode 的三个数据版本,分别是当前znode版本,当前znode 子节点版本,当前znode acl版本。

watcher 即事件监听器,是zookeeper 中一个很重要的特性,允许用户在指定节点上注册一些watcher ,并且在一些特定事件触发的时候,zk 服务端会将事件通知到感兴趣的客户端上,该机制是zK 实现分布式协调服务的重要特性。

ACL

采用ACL 策略进行权限控制,定义了五种权限,

CREATE 创建子节点的权限

READ 获取节点数据和子节点列表的权限

WRITE 更新节点数据的权限

DELETE 删除子节点的权限

ADMIN 设置节点ACL的权限

ZK 的ZAB 协议

Zookeeper Atomic Broadcast zk 原子消息广播协议。 作为其数据一致性的核心算法。

是为zk专门设计的一种支持奔溃恢复的原子关闭协议。

zk中,主要依赖ZAB协议来实现分布式数据一致性。基于该协议,zk实现了一种主备模式的系统架构来保持集群中各副本之间的数据一致性。

具体来说,zk使用一个单一的主进程来接受并处理客户端的所有事务请求,并采用ZAB的原子广播协议,将服务器数据的状态变更以事务proposal的形式广播到所有的副本进程上去,ZAB的这个主备模型架构保证了同一时刻集群中只有一个主进程来广播服务器的状态变更,因此能够很好的处理客户端大量的并发请求。

ZAB协议包括两种基本的模式,分别是崩溃恢复和消息广播,当服务框架启动过程中,或者是当leader服务器出现网络中断,奔溃退出或者重启等异常状况时,ZAB就会进入恢复模式并选举出新的leader服务器。当选举出leader服务器并且集群中已经有过半的机器与该leader服务器完成了状态同步之后,ZAB就会退出恢复模式,其中,状态同步就是指数据同步。

当集群中有过半follower完成了与leader的状态同步后,整个服务框架就可以进入消息广播模式了,当一台同样遵守ZAB的服务器启动加入集群中时,如果集群中已经存在一个leader进行广播,新加入的服务器就会自觉地进入数据恢复模式,即找到leader服务器,并与其进行数据同步,然后一起参与到消息广播流程中。

当leader服务器出现崩溃或者重启,或者集群中已经不存在过半的服务器与该leader服务器保持正常通信时,那么在重新开始新一轮的原子广播事务操作之前,所有进程会首先使用崩溃协议来使彼此达到一个一致的状态,ZAB流程会从消息广播模式进入崩溃恢复阶段。

消息广播

消息广播使用的是原子广播协议,类似一个二阶段提交过程,针对客户端的事务请求,leader服务器会为其生成对应的事务proposal,并将其发送给集群中其余所有机器,然后再分别收集各自的选票,最后进行事务提交。即先发送propose,受到半数Ack,然后再发送commit 进行提交。

在整个消息广播过程中,leader 服务器会为每个事务请求生成对应的proposal来进行广播,并且在广播事务proposal之前,leader服务器会首先为这个事务proposal分配一个全局递增的唯一ID,称之为事务ID. 由于ZAB还要保证消息严格的因果关系,因此必须将每个事务proposal按照其事务ID的先后顺序排序与处理。

崩溃恢复

一旦leader服务器出现崩溃,或者网络原因导致leader 服务器失去了与过半follower 的联系,就会进入崩溃恢复模式,在ZAB协议中,为了保证程序正确运行,整个恢复过程结束后需要选举一个新的leader 服务器。因此,ZAB需要一个高效可靠的leader选举算法。

leader选举算法应该能够确保提交已经被leader提交的事务proposal,同时丢弃已经被跳过的事务proposal。

针对这个要求,如果让leader选举算法能够保证新选举出来的leader 服务器拥有集群中所有机器最高编号的事务proposal ,那么就可以保证这个新选举的leader一定具有所有已经提交的提案,更为重要的是,如果让具有最高编号事务proposal 的机器来成为leader,就可以省去leader 服务器检查proposal 的提交和丢弃工作的这一步操作了。