————— 第二天 —————
————————————
ZooKeeper 的数据模型
ZooKeeper 的数据模型是什么样子呢?它很像数据结构当中的树,也很像文件系统的目录。
树是由节点所组成,ZooKeeper 的数据存储也同样是基于节点,这种节点叫做Znode。
但是,不同于树的节点,Znode 的引用方式是路径引用,类似于文件路径:
/ 动物 / 仓鼠
/ 植物 / 荷花
这样的层级结构,让每一个 Znode 节点拥有唯一的路径,就像命名空间一样对不同信息作出清晰的隔离。
data:Znode 存储的数据信息。
ACL:记录 Znode 的访问权限,即哪些人或哪些 IP 可以访问本节点。
stat:包含 Znode 的各种元数据,比如事务 ID、版本号、时间戳、大小等等。
child:当前节点的子节点引用,类似于二叉树的左孩子右孩子。
这里需要注意一点,ZooKeeper 是为读多写少的场景所设计。Znode 并不是用来存储大规模业务数据,而是用于存储少量的状态和配置信息,每个节点的数据最大不能超过 1MB。
ZooKeeper 的基本操作和事件通知
ZooKeeper 包含了哪些基本操作呢?这里列举出比较常用的 API:
create:创建节点
delete:删除节点
exists:判断节点是否存在
getData:获得一个节点的数据
setData:设置一个节点的数据
getChildren:获取节点下的所有子节点
这其中,exists、getData、getChildren 属于读操作。ZooKeeper 客户端在请求读操作的时候,可以选择是否设置 Watch。
Watch 是什么意思呢?
我们可以理解成是注册在特定 Znode 上的触发器。当这个 Znode 发生改变,也就是调用了 create、delete、setData 方法的时候,将会触发 Znode 上注册的对应事件,请求 Watch 的客户端会接收到异步通知。
具体交互过程如下:
1. 客户端调用 getData 方法,Watch 参数是 true。服务端接到请求,返回节点数据,并且在对应的哈希表里插入被 Watch 的 Znode 路径,以及 Watcher 列表。
2. 当被 Watch 的 Znode 已删除,服务端会查找哈希表,找到该 Znode 对应的所有 Watcher,异步通知客户端,并且删除哈希表中对应的 Key-Value。
ZooKeeper 的一致性
ZooKeeper 的集群长成什么样呢?就像下图这样:
ZooKeeper Service 集群是一主多从结构。
更新数据时,首先更新到主节点(这里的节点是指服务器,不是 Znode),再同步到从节点。
在读取数据时,直接读取任意从节点。
为了保证主从节点的数据一致性,ZooKeeper 采用了ZAB 协议,这种协议非常类似于一致性算法 Paxos 和 Raft。
在学习 ZAB 之前,我们需要首先了解 ZAB 协议所定义的三种节点状态:
Looking:选举状态。
Following:Follower 节点(从节点)所处的状态。
Leading:Leader 节点(主节点)所处状态。
我们还需要知道最大 ZXID 的概念:
最大 ZXID 也就是节点本地的最新事务编号,包含 epoch 和计数两部分。epoch 是纪元的意思,相当于 Raft 算法选主时候的 term。
假如 ZooKeeper 当前的主节点挂掉了,集群会进行崩溃恢复。ZAB 的崩溃恢复分成三个阶段: