ZooKeeper-基本概念
1、角色
1.1、集群模式
1.1.1、简介
基本上所有的集群模式中的主机都有自己的角色,最为典型的集群模式就是 M/S 主备模式。在这种模式下,我们把处于主要地位(处理写操作)的主机称为 Master 节点,处于次要地位(处理读操作)的主机称为
Slave 节点,生产中读取的方式一般是以异步复制方式来实现的。
1.1.2、主备架构图
Zookeeper集群就是这种M/S的模型,集群通常由2n+1台Server节点组成,每个Server都知道彼此的存在。对于2n+1台server,只要有>=(n+1)台server节点可用,整个Zookeeper系统保持可用。
1.2、角色划分
注意:角色是Zookeeper内部的业务场景角色,不是集群节点职责角色。
1.2.1、领导者(Leader)
领导者不接受client读请求,负责进行投票发起和决议,更新系统状态
1.2.2、跟随者(Follower)
接收客户请求并向客户端返回结果,在选Leader过程中参与投票
1.2.3、观察者(Observer)
转交客户端写请求给leader节点,和同步leader状态,不参与选举投票
1.2.4、学习者(Learner)
和leader进行状态同步的节点统称Learner,Follower和Observer都是
1.2.5、客户端(client)
请求发起方
1.3、角色解析
1.3.1、简介
Zookeeper集群系统启动时,集群中的主机会选举出一台主机为Leader,其它的就作为Learner(包括Follower和Observer)。接着由follower来服务client的请求,对于不改变系统一致性状态的读操作,
由follower的本地内存数据库直接给client返回结果;对于会改变Zookeeper系统状态的更新操作,则交由Leader进行提议投票,超过半数通过后返回将结果给client。
1.3.2、数据操作流程图
1.3.3、ZAB协议说明
Zookeeper是采用ZAB协议(Zookeeper Atomic Broadcast,Zookeeper原子广播协议)来保证主从节点数据一致性的,ZAB协议支持「崩溃恢复和消息广播」两种模式,很好解决了这两个问题:
1、崩溃恢复:
Leader挂了,进入该模式,选一个新的leader出来,接着,新的Leader服务器与集群中Follower服务进行数据同步,当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式。
2、消息广播:
把更新的数据,从Leader同步到所有Follower Leader 服务器开始接收客户端的事务请求生成事务Proposal进行事务请求处理。
1.4、主机状态
Zookeeper集群中每个Server主机在工作过程中有四种状态:
Looking(迷茫者):我老大是谁?
当前Server主机不知道集群中的Leader是谁,陷入深深的不安,正在搜寻主心骨。
Leading(领导者):我是总统。
当前Server主机被集群选举策略确定的Leader,我的地盘我做主。
Following(执行者):我是员工。
集群的Leader主机已经选举出来,当前Server主机与之同步信息,严格执行规章制度,保质保量
完成任务。
Observing(观望者): 我是看客
observer会观察leader是否有改变,然后同步leader的状态,是系统扩展的一种方法
1.5、事务id
所谓的事务id -- zxid。ZooKeeper的在选举时通过比较各结点的zxid和机器ID选出新的主结点的。 zxid由Leader节点生成,有新写入事件时,Leader生成新zxid并随提案一起广播,每个结点本地都保存了当前最近一次事务的zxid,zxid是递增的,所以谁的zxid越大,就表示谁的数据是最新的。
ZXID有两部分组成: 任期:完成本次选举后,直到下次选举前,由同一Leader负责协调写入; 事务计数器:单调递增,每生效一次写入,计数器加一。 --同一任期内,ZXID是连续的,每个结点又都保存着自身最新生效的ZXID,通过对比新提案的ZXID与自身最新ZXID是否相差“1”,来保证事务严格按照顺序生效的。
2、会话
2.1、基础知识
会话(Session)指客户端启动时候和Zookeeper集群主机节点之间创建的 TCP 长连接。
既然是会话,那么就必须说该会话的生命周期:
会话是从客户端和服务端第一次连接建立开始算起。通过这个连接,客户端能够通过心跳检测与服务节点保持有效的会话,并向 Zookeeper 服务器发送请求并接收响应,以及接收来自服务端的监听事件通知
2.2、会话状态
客户端和Zookeeper集群主机建立连接,整个session状态变化如图所示
如果Client因为Timeout和Zookeeper Server失去连接,client处在CONNECTING状态,会自动尝试再去连接Server,
如果在session有效期内再次成功连接到某个Server,则回到CONNECTED状态,否则的话,原来的会话中断,进入CLOSED状态。
注意:
如果因为网络状态不好,client和Server失去联系,client会停留在当前状态,会尝试主动再次连接
Zookeeper Server。client不能宣称自己的session expired,session expired是由Zookeeper Server来决定的,client可以选择自己主动关闭session。
2.3、流程解析图
3、数据模型
3.1、基础知识
3.1.1、简介
在 Zookeeper 中,节点分为两类:
第一类是指 构成Zookeeper集群的主机,称之为主机节点;
第二类则是指内存中 Zookeeper数据模型中的数据单元,用来存储各种数据内容,称之为数据节点 ZNode。
Zookeeper内部维护了一个层次关系(树状结构)的数据模型,它的表现形式类似于linux的文件系统,甚至操作的种类都一致。
Zookeeper数据模型中有自己的根目录(/),根目录下有多个子目录,每个子目录后面有若干个文件,由斜杠(/)进行分割的路径,就是一个 ZNode,每个 ZNode 上都会保存自己的数据内容 和 一系列属性信息。
3.1.2、样式
注意:
ZNode是一个类似树状结构,有自己的根节点和子节点。
每个子目录项都是ZNode,这个ZNode是被它所在的路径唯一标识,如App1的znode的标识为/Apps/App1
每个ZNode都有自己对应的目录路径和内部的文件数据,当Zookeeper的客户端在和服务端创建连接后,服务端会给客户端创建一个会话(Session),Zookeeper客户端就可以在这个会话中,对自己的ZNode进行增删改查等操作了。
也就是说:ZNode的所有操作是随着Zookeeper的连接/断开实现的。
3.2、类型解析
3.2.1、简介
虽然ZNode的样式跟Linux文件系统类似,根据节点的生命周期,在Zookeeper中的ZNode有四种独有的特性,有时候页称为四种类型: 1、基本节点: Persistent(持久节点):会话断开后,除非主动进行移除操作,否则该节点一直存在 Ephemeral(临时节点):会话断开后,该节点被删除 2、序列节点: Persistent Sequential:按顺序编号的持久节点 该节点被创建的时候,Zookeeper 会自动在其子节点名上,加一个由父节点维护的、自增整数的后缀 Ephemeral Sequential:按顺序编号的临时节点 该节点被创建的时候,Zookeeper 会自动在其子节点名上,加一个由父节点维护的、自增整数的后缀 注意: 只有持久性节点(持久节点和顺序持久节点)才有资格创建子节点 3、自增后缀格式: 10位10进制数的序号 4、有序和无序区别: 多个客户端同时创建同一无序ZNode节点时,只有一个可创建成功,其它匀失败。并且创建出的节点名称与创建时指定的节点名完全一样 多个客户端同时创建同一有序ZNode节点时,都能创建成功,只是序号不同。
3.2.2、功能简介
Zookeeper使用这个基于内存的树状模型来存储分布式数据,正因为所有数据都存放在内存中,所以Zookeeper才能实现高性能的目的,提高数据的吞吐率。特别是在集群主机节点间的数据同步。
Znode包含了 存储数据(data)、访问权限(acl)、子节点引用(child)、节点状态(stat)信息等信息
注意:
为了保证高吞吐和低延迟,以及数据的一致性,znode只适合存储非常小的数据,不能超过1M,最好都小于1K
4、版本
4.1、业务需求
工作中,Zookeeper在服务架构中,主要是做服务注册和服务发现的角色的,这两个功能主要体现在服务的配置文件上,而由于服务的版本更新,所以配置文件也需要有相应的版本控制功能,版本控制的本质就是历史记录的追踪,即"溯源性"。 那么如何将这些不同版本的配置信息都存储下来呢?Zookeeper的ZNode提供了一个"版本"的功能来解决这个问题。
4.2、版本样式
ZNode中可以基于"版本"的功能来存储多版本的数据,其实就是在一个访问路径中可以访问不同版本的数据,存储的样式就是,在同一个ZNode目录中使用多个子目录来存储不同版本的数据,只不过每份数据的version号是自动增加的。
4.3、数据结构
Zookeeper 的 ZNode 上都会存储数据,对应于每个 ZNode,Zookeeper 都会为其维护一个叫做 Stat 的数据结构,Stat 中记录了这个 ZNode 的三个数据版本:
dataversion 当前 ZNode 数据内容的版本
cversion 当前 ZNode 子节点的版本
aversion 当前 ZNode 的 ACL 变更版本。
这里的版本起到了控制 Zookeeper 操作原子性的作用,基于这些功能,才能更好实现了分布式锁的功能。
5、监听
5.1、监听简介
Watcher(事件监听器)是 Zookeeper 提供的一种 发布/订阅的机制。
Zookeeper 允许客户端在指定的集群数据节点上注册一些 Watcher,当发生ZNode存储数据的修改,子节点目录的变化等情况的时候,Zookeeper 服务端会将事件通知给监听的客户端,然后客户端根据Watcher通知状态和事件类型做出业务上的改变。
该机制是 Zookeeper 实现分布式协调的重要特性,也是Zookeeper的核心特性,Zookeeper的很多功能都是基于这个特性实现的。
-- 这个过程是异步的。
5.2、工作原理
5.2.1、原理图
5.2.2、说明
ZooKeeper的Watcher机制主要包括客户端线程、客户端 WatcherManager、Zookeeper服务器三部分。
客户端向ZooKeeper服务器注册Watcher的同时,会将Watcher对象存储在客户端的WatchManager中。
当zookeeper服务器触发watcher事件后,会向客户端发送通知, 客户端线程从 WatcherManager 中取出对应的 Watcher 对象来执行回调逻辑。
5.2.3、关键点
Zookeeper的监听机制主要有三个关键点:整体触发、发送方式、局部触发。
整体触发:
当设置监视的数据发生改变时,该监视事件会被发送到客户端,常见的就是监控ZNode中的数据或子目录发生变化。
发送方式:
Zookeeper服务端被触发的时候,会基于会话给客户端发送信息,但是由于网络的原因,经常会出现网络延迟的因素,造成客户端接收的结构不一致,而Zookeeper有一个很重要的特点就是:一致性,为了达到这个目标,Zookeeper的监听机制在信息发送的方式上,就有了一个发送特点:
所有的监视事件被触发后,不会立即发送至客户端,而是以异步的方式发送至监视者的,而且Zookeeper 本身提供了顺序保证。效果就是:客户端首先看到监视事件,然后才会感知到它所设置监视的znode发生了变化。
这样就达到了,虽然不同的客户端在不同的时刻感知到了监视事件,但是客户端所看到的效果都是真实一致的。
局部触发
当客户端监视的Zookeeper节点ZNode内部有比较多的子目录数据的时候,这种场景下,我们只需要监视其中的一个小部分重要的数据,其他的数据是一些无关紧要的,所以就没有必要监视全部的ZNode数据变化,
这意味着znode节点本身就应该具有不同的触发事件方式:即支持对ZNode数据事件的局部触发。
5.3、原理解析图
5.4、异常处理
Zookeeper 中的监视功能是轻量级的,易设置、维护和分发。
当客户端与 Zookeeper 服务器失去联系时,客户端并不会收到监视事件的通知,只有当客户端重新连接后,若在必要的情况下,以前注册的监视会重新被注册并触发,对于开发人员来说这通常是透明的。
只有一种情况会导致监视事件的丢失。即通过设置了某个znode节点的监视,但是如果某个客户端在此znode节点被创建和删除的时间间隔内与zookeeper服务器失去了联系,该客户端即使稍后重新连接zookeeper服务器后也得不到事件通知。