Zookeeper的工作机制
什么是ZooKeeper
ZooKeeper 是一个分布式协调服务,其设计的初衷是为分布式软件提供一致性服务。其本质上,就是文件系统+通知机制。
ZooKeeper 提供了一个类似 Linux 文件系统的树形结构,ZooKeeper 的每个节点既可以是目录也可以是数据,并且 ZooKeeper 还提供了对每个节点的监控与通知机制。
ZooKeeper 的工作机制
ZooKeeper 采用的是主从模式,有主节点和从节点。从设计模式的角度,它是一个基于观察者模式设计的分布式服务管理框架,负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,ZooKeeper 就将负责通知已经注册的那些观察者做出相应的反应。
Zookeeper角色及其关系
ZooKeeper 中的角色包括 Leader、Follower、Observer。
其中,Leader 为集群主节点,主要负责管理集群状态和接收用户的写请求;Follower 为从节点,主要负责集群选举投票和接收用户的读请求;Observer 的功能与 Follower 类似,只是没有投票权,主要用于分担 Follower 的读请求,降低集群的负载。
Leader
一个运行中的 Zookeeper 集群只有一个 Leader 服务,Leader 服务主要包括以下两个职责:
-
负责集群数据的写操作。所有写操作必须要 Leader 完成之后,才可以将写操作广播到其他 Follower,并且只有超过半数节点(不包括 Observer)写入成功后,这些写请求才算写成功;
-
发起并维护各个 Follower 以及 Observer 之间的心跳,以监控集群的运行状态。
Follower
一个 Zookeeper 集群可以有多个 Follower,Follower通过心跳与 Leader 保持连接。Follower 服务主要有以下两个职责:
-
负责集群数据的读操作。Follower 在接受到一个客户端请求之后,会先判断该请求是读请求还是写请求,若为读请求,则 Follower 从本地节点上读取数据并返回给客户端;若为写请求,则 Follower 会将写请求转发给 Leader 来处理;
-
参与集群中 Leader 的选举。当 Leader 失效之后,Follower 需要在集群选举时进行投票;
Observer
一个 Zookeeper 集群可以有多个 Observer,Observer 的主要职责是负责集群数据的读操作,其功能同以上介绍的 Follower 的功能类似,主要的差别就是 Observer 没有投票权。
Follower 已经具备了 Observer 的所有功能,为什么还要设计 Observer 角色 ?
这是因为 ZooKeeper 集群在运行过程中要支持更多的客户端并发的操作,就需要增加更多的服务实例,而过多的服务实例会使得集群的投票阶段变得复杂,选举时间过长不利于集群故障的快速恢复。
因此,ZooKeeper 引入了 Observer 角色,Observer 不参与投票,只负责接收客户端来的读请求,以及将写请求转发给 Leader 。加入更多的 Observer 节点,不仅提高了 ZooKeeper 集群的吞吐量,保障了系统的稳定性。
Zookeeper中的ZAB协议
什么是ZAB
ZAB(ZooKeeper Atomic Broadcast,ZooKeeper 原子消息广播协议)是一种分布式一致性协议。(类似于raft?)
两个概念
当前集群周期号Epoch
集群中每次 Leader 的重新选举都会产生一个新的周期号(也有叫年代号的,都一个意思),周期号的产生规则则是在上一个周期号上加1,这样当之前的 Leader 奔溃恢复后会发现自己的周期号比当前的周期号小,说明此时集群已经产生了一个新的 Leader,旧的 Leader 会再次以 Follower 的角色加入集群。
ZAB协议的事务编号Zxid
Zxid 是一个64位的数字,其中低32位存储的是一个简单的单调递增的计数器,针对客户端的每个事务请求,计数器都会加1。高32位存储的是 Leader 的周期号 Epoch。每次选举产生一个新的 Leader 时,该 Leader 就会从当前服务器的日志中取最大事务的 Zxid,获取其中高32位的 Epoch 值并加1,以此作为一个新的 Epoch,并会将低32位从0开始重新计数。
两种模式
集群选主-恢复模式
当集群 Leader 出现崩溃,或者由于网络原因导致 Leader 和过半的 Follower 失去联系,那么集群将开始选主,该过程为恢复模式。
Leader 的选举机制不仅可以让 Leader 节点知道自身被选举为 Leader,同时还能需要让集群中其他节点也能快速感知到选举的新的 Leader 节点。
数据同步-广播模式
当 Leader 被选举出来后,Leader 将最新的集群状态广播给其他 Follower,该过程为广播模式。在半数以上的 Follower 完成与 Leader 的状态同步后,广播模式结束。
ZAB实现过程
选举阶段
选举阶段的目的就是产生一个准 Leader,节点在一开始都处于选举阶段,只要有一个节点得到超过半数节点的票数,那么它就可以当选准Leader,只有到达第三阶段(同步阶段)这个准Leader才会成为真正的Leader。
发现阶段
在该阶段中 Follower 和上一阶段选举出的准 Leader 进行通信,同步 Follower 最近接收的事务提议。这一阶段的目的是发现当前大多数节点接收的最新提议,并且准 Leader 生成新的 epoch,并让 Follower 接收,更新它们的 acceptedEpoch。
同步阶段
同步阶段主要是将 Leader 在前一阶段获得的最新提议信息同步到集群中所有的副本。并且只有当超过半数的节点都同步完成后,准 Leader 才会成为真正的 Leader 。Follower 只会接收 Zxid比自己 lastZxid 大的提议。
广播阶段
在该阶段,ZooKeeper 集群正式对外提供事务服务,这时 Leader 进行消息广播,将其上的状态通知到其他 Follower。若后续有新的节点加入进来,则 Leader 会对新节点进行状态同步。
Zookeeper的数据模型
ZooKeeper 使用了一个树形结构的命名空间来表示其数据结构,其视图结构和标准的 Unix 文件系统非常类似,但没有引入传统文件系统中目录和文件等相关概念,而是将 ZooKeeper 树中的每一个节点都称之为一个 Znode。其数据结构如下图所示。
Znode的数据模型
Znode 是 ZooKeeper 中数据的最小单元,每个 Znode 都兼具文件和目录两种特点,既能像文件一样保存和维护数据,又可以由一系列使用斜杠(/)进行分割的方式作为路径标识的一部分。每个 Znode 都有以下三部分组成。
-
Stat:状态信息,用于存储该 Znode 的版本、权限、时间戳等信息;
-
Data:实际存储的数据;
-
Children:对子节点的信息描述;
需要特别说明的是,Znode 节点虽然可以存储数据信息,但它并不能像数据库那样存储大量的数据,Znode 的设计初衷就是存储分布式应用中的配置文件、集群状态等元数据信息。
Znode的控制访问
ACL
ACL(Access Control List) 为访问控制列表,应用程序会根据实际需求将用户分为只读、只写以及读写用户,每一个 Znode 节点都会有一个 ACL 用来约束不同的用户对节点的访问权限。
原子操作
每一个 Znode 节点上都具有原子操作的特性,读操作将获取与节点相关的数据,写操作将替换节点上的数据,上期文章中讲到 ZooKeeper 都会为每一个事务请求分配一个全局唯一的事务编号 Zxid,每一个 Zxid 就对应一次更新操作,并可以通过 Zxid 来识别出更新操作请求的全局顺序。
Znode节点类型
临时节点
临时节点常被应用于心跳监控,举个栗子,设置过期时间为 30s,要求各个子节点对应的服务端每 5s 发送一次心跳到 ZooKeeper 集群,当服务端连续 30s 没有向 ZooKeeper 汇报心跳信息,也就是连续6次没有收到心跳信息,就认为该节点宕机了,并将其从服务列表中移除。
临时节点的生命周期依赖于创建它们的会话(Session)。一旦会话结束,临时节点将被自动删除,当然可以也可以手动删除。
另外,ZooKeeper 的临时节点不允许拥有子节点。
永久节点
永久节点的数据会一直存储着,直到用户调用接口将其数据删除,该节点一般用于存储一些永久性的配置信息。
Znode监听机制(重点)
ZooKeeper 的每个节点上都有一个 Watcher 用于监控节点数据的变化,当节点状态发生改变时(Znode 新增、删除、修改)将会触发 Wahcher 所对应的操作。在 Watcher 被触发时,ZooKeeper 会向监控该节点的客户端发送一条通知说明节点的变化情况。
具体实现流程就是,客户端向 ZooKeeper 服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的 WatchManager 中。当 ZooKeeper 服务器端触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatchManager 中取出对应的 Watcher 对象来执行回调逻辑。