zookeeper笔记整理(二)

Watcher 节点事件监听

​ zookeeper 提供了分布式数据的发布/订阅功能, zookeeper允许客户端向服务端注册一个 watcher 监听。

​ 当服务端的一些指定事件(比如可以监听节点数据变更、节点删除、子节点状态变更等 )触发了 watcher,那么服务端就会向客户端发送 一个事件通知。

​ 值得注意的是, Watcher 通知是一次性的,即一旦触发一次通知后,该 Watcher 就失效了,因此如果要实现永久监听,可以通过循环注册来实现

​ 通过这个事件机制,可以基于 zookeeper 实现分布式锁、集群管理等功能

实现分布式锁

利用 zookeeper 节点的特性来实现独占锁,就是同级节点的唯一性,多个进程往 zookeeper 的指定节点下创建一个相同名称的节点,只有一个能成功,另外一个是创建失败;

创建失败的节点全部通过 zookeeper 的 watcher 机制来监听 zookeeper 这个子节点的变化,一旦监听到子节点的删除事件,则再次触发所有进程去写锁;

存在的问题

​ 实现方式很简单,但是会产生“惊群效应”,简单来说就是如果存在许多的客户端在等待获取锁,当成功获取到锁的进程释放该节点后,所有处于等待状态的客户端都会被唤醒。

​ 这个时候 zookeeper 在短时间内发送大量子节点变更事件给所有待获取锁的客户端,然后实际情况是只会有一个客户端获得锁。

​ 如果在集群规模比较大的情况下,会对 zookeeper 服务器的性能产生比较的影响。

利用有序节点来实现分布式锁

​ 通过有序节点来实现分布式锁,每个客户端都往指定的节点下注册一个临时有序节点,越早创建的节点,节点的顺序编号就越小,那么我们可以判断子节点中最小的节点设置为获得锁。

​ 每个节点只需要监听比自己小的节点,当比自己小的节点删除以后,客户端会收到 watcher 事件,此时再次判断自己的节点是不是所有子节点中最小的,如果是则获得锁,否则就不断重复这个过程,这样就不会导致惊群效应。

Zookeeper 的 Java 访问框架

针对 zookeeper,比较常用的 Java 客户端有 zkclient、curator。由于 Curator 对于 zookeeper 的抽象层次比较高,简化了zookeeper 客户端的开发量。使得 curator 逐步被广泛应用。

ACL 权限控制

为了保证 zookeeper 中的数据的安全性,避免误操作带来的影响。 Zookeeper 提供了一套 ACL 权限控制机制来保证数据的安全。

(1)ZooKeeper 提供了如下几种验证模式:

1)IP
通 过 ip 地 址 粒 度 来 进 行 权 限 控 制 , 例 如 配 置[ip:192.168.0.1], 或者按照网段 ip:192.168.0.1/24 ;

2)digest
digest模式是最常用的一种模式,形如"username:password"的方式。

3)World
World模式其实是一种开放的模式,即对所以用户开放,设置格式是"world:anyone",事实上这种模式没什么效果,因为设置了也对所有人开放

4)Super
Super模式是超级管理员模式,超级管理员可以对任何节点进行操作

(2)权限类型

指通过权限检查后可以被允许的操作 , create /delete/read/write/admin
Create 允许对子节点 Create 操作
Read 允许对本节点 GetChildren 和 GetData 操作
Write 允许对本节点 SetData 操作
Delete 允许对子节点 Delete 操作
Admin 允许对本节点 setAcl 操作

Leader选举

实际使用ZooKeeper开发中,我们最常用的是Apache Curator。 它由Netflix公司贡献给Apache。Curator 有两种选举 recipe(Leader Latch 和 Leader Election)

Leader Latch

​ 参与选举的所有节点,会创建一个顺序节点,其中最小的节点会设置为 master 节点, 没抢到 Leader 的节点都监听前一个节点的删除事件。

​ 在前一个节点删除后进行重新抢主,当 master 节点手动调用 close()方法或者 master节点挂了之后, 后续的子节点会抢占 master。其中 spark 使用的就是这种方法

LeaderSelector

LeaderSelector 和 Leader Latch 最大的差别在于, leader可以释放领导权以后,还可以继续参与竞争

Zookeeper 数据同步

见下方ZAB(Zookeeper Atomic Broadcast) 协议

ZAB协议

​ ZAB(Zookeeper Atomic Broadcast) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。

​ ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性 。

​ ZAB 协议包含两种基本模式,分别是 :崩溃恢复 和 原子广播

恢复模式介绍

​ 当整个集群在启动时,或者当 leader 节点出现网络中断、崩溃等情况时, ZAB 协议就会进入恢复模式并选举产生新的 Leader,当 leader 服务器选举出来后,并且集群中有过半的机器和该 leader 节点完成数据同步后, ZAB 协议就会退出恢复模式。

​ 在 Leader 节点正常工作时,启动一台新的服务器加入到集群,那这个服务器会直接进入恢复模式

广播模式介绍

​ 当集群中已经有过半的 Follower 节点完成了和 Leader 状态同步以后,那么整个集群就进入了消息广播模式。

​ leader 节点可以处理事务请求和非事务请求, follower 节点只能处理非事务请求,如果 follower 节点接收到非事务请求,会把这个请求转发给 Leader 服务器

消息广播原理

消息广播的过程实际上是一个简化版本的二阶段提交过程

  1. leader 接收到消息请求后,将消息赋予一个全局唯一的64 位自增 id,叫: zxid,通过 zxid 的大小比较既可以实现因果有序这个特征
  2. leader 为每个 follower 准备了一个 FIFO 队列(通过 TCP协议来实现,以实现了全局有序这一个特点)将带有 zxid的消息作为一个提案(proposal)分发给所有的 follower
  3. 当 follower 接收到 proposal,先把 proposal 写到磁盘,写入成功以后再向 leader 回复一个 ack
  4. 当 leader 接收到合法数量(超过半数节点)的 ACK 后,leader 就会向这些 follower 发送 commit 命令,同时会在本地执行该消息
  5. 当 follower 收到消息的 commit 命令以后,会提交该消息

和完整的 2pc 事务不一样的地方在于, zab 协议不能终止事务

崩溃恢复的实现原理

​ 一旦 Leader 节点崩溃,或者由于网络问题导致 Leader 服务器失去了过半的Follower 节点的联系那么就会进入到崩溃恢复模式。

崩溃恢复状态下 zab 协议需要做两件事:

-1. 选举出新的 leader
-2. 数据同步

需要解决两个问题:

1.已经被处理的消息不能丢

这种是服务器leader已经发广播commit出去了,并向连接的客户端返回「成功」,然后崩溃或失联,为了最终能够在所有的服务器上执行,这种消息不能丢了。

2.被丢弃的消息不能再次出现

场景:当 leader 接收到消息请求生成 proposal 后挂了,其他 follower 并没有收到此 proposal,很久之后挂了的 leader 重新启动并注册成了 follower,他保留了被跳过消息的proposal 状态,与整个系统的状态是不一致的,需要将其删除。

实现办法:

1.保证新选举出来的 Leader 服务器拥所有机器最高编号(消息ZXID 最大)的事务Proposal,那么就可以保证这个新选举出来的 Leader 一定具有已经提交的提案。

因为所有提案被 COMMIT 之前必须有超过半数的 follower ACK,即必须有超过半数节点的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保存了所有被COMMIT 消息的 proposal 状态

2.另外, zxid(消息id) 是 64 位:

高 32 位是 epoch 编号,每经过一次 Leader 选举产生一个新的 leader,新的 leader会将 epoch 号+1,

低 32 位是消息计数器,每接收到一条消息这个值+1,新 leader 选举后这个值重置为 0.

这样设计在于老 leader 挂了后重启,不会选举为 leader,因它的 zxid 肯定小于当前新leader。老 leader 作为 follower 接入新 leader后,新 leader 会让它拥有旧的 epoch 号未被 COMMIT 的 proposal 清除

ZXID

​ zxid,也就是事务 id ,为了保证事务的顺序一致性, zookeeper 采用了递增的事务 id 号(zxid)来标识事务 。所有的提议(proposal)都在被提出的时候加上了 zxid。

​ zxid 是一个 64 位的数字,它高 32 位是 epoch,用来标识 leader 关系是否改变,每次一个 leader 被选出来,它都会有一个新的epoch=(原来的 epoch+1,低 32 位用于递增计数。

​ epoch:可以理解为当前集群所处的年代或者周期,每个leader 就像皇帝,都有自己的年号,所以每次改朝换代, leader 变更之后,都会在前一个年代的基础上加1。这样就算旧的 leader 崩溃恢复之后,也没有人听他的了,因为 follower 只听从当前年代的 leader 的命令。

你可能感兴趣的:(zookeeper笔记整理(二))