Zookeeper是什么

  • ZooKeeper 是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态。

  • 根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

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

Zookeeper 特性

Zookeeper 保证了如下分布式一致性特性

  1. 顺序一致性:从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。

  2. 原子性:所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。

  3. 单一视图:无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。

  4. 可靠性:一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会被一直保留下来。

  5. 实时性(最终一致性): Zookeeper 仅仅能保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。

ZooKeeper 提供了什么?

  1. 文件系统

  2. 通知机制

Zookeeper 文件系统

Zookeeper 提供一个多层级的节点命名空间(节点称为 znode)。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。

Zookeeper 为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得 Zookeeper 不能用于存放大量的数据,每个节点的存放数据上限为1M

ZAB 协议?

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

ZAB 协议包括两种基本的模式:崩溃恢复和消息广播

  • 当整个 zookeeper 集群刚刚启动或者 Leader 服务器宕机、重启或者网络故障导致不存在过半的服务器与 Leader 服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的 Leader 服务器,然后集群中 Follower 服务器开始与新的 Leader 服务器进行数据同步,当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式。

  • 接着进入消息广播模式,Leader 服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。

四种类型的数据节点 Znode

  1. 持久节点(PERSISTENT):这类节点被创建后,就会一直存在于zk服务器上,直到手动删除。

  2. 持久顺序节点(PERSISTENT_SEQUENTIAL):它的基本特性同持久节点,不同在于增加了顺序性。父节点会维护一个自增整性数字,用于子节点的创建的先后顺序。

  3. 临时节点(EPHEMERAL):临时节点的生命周期与客户端的会话绑定,一旦客户端会话失效(非TCP连接断开),那么这个节点就会被自动清理掉。zk规定临时节点只能作为叶子节点。

  4. 临时顺序节点(EPHEMERAL_SEQUENTIAL):基本特性同临时节点,添加了顺序的特性。

Zookeeper Watcher 机制 – 数据变更通知

Watcher监听机制
Zookeeper 允许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher通知状态和事件类型做出业务上的改变。

可以把Watcher理解成客户端注册在某个Znode上的触发器,当这个Znode节点发生变化时(增删改查),就会触发Znode对应的注册事件,注册的客户端就会收到异步通知,然后做出业务的改变。

Chroot 特性

3.2.0 版本后,添加了 Chroot 特性,该特性允许每个客户端为自己设置一个命名空间。如果一个客户端设置了 Chroot,那么该客户端对服务器的任何操作,都将会被限制在其自己的命名空间下。通过设置 Chroot,能够将一个客户端应用于 Zookeeper 服务端的一颗子树相对应,在那些多个应用公用一个 Zookeeper 进群的场景下,对实现不同应用间的相互隔离非常有帮助。

服务器角色

Leader

  1. 事务请求的唯一调度和处理者,保证集群事务处理的顺序性。

  2. 集群内部各服务的调度者。

Follower

  1. 处理客户端的非事务请求,转发事务请求给 Leader 服务器。

  2. 参与事务请求 Proposal 的投票。

  3. 参与 Leader 选举投票。

Observer

  1. 3.0 版本以后引入的一个服务器角色,在不影响集群事务处理能力的基础上提升集群的非事务处理能力。

  2. 处理客户端的非事务请求,转发事务请求给 Leader 服务器。

  3. 不参与任何形式的投票。

Zookeeper 下 Server 工作状态

服务器具有四种状态,分别是 LOOKING、FOLLOWING、LEADING、OBSERVING。

  1. LOOKING:寻找 Leader 状态。当服务器处于该状态时,它会认为当前集群中没有 Leader,因此需要进入 Leader 选举状态。

  2. FOLLOWING:跟随者状态。表明当前服务器角色是 Follower。

  3. LEADING:领导者状态。表明当前服务器角色是 Leader。

  4. OBSERVING:观察者状态。表明当前服务器角色是 Observer。

Znode节点里面存储的是什么

Znode数据节点的代码如下:

1
2
3
4
5
6
public class DataNode implements Record {
byte data[];
Long acl;
public StatPersisted stat;
private Set<String> children = null;
}

Znode包含了存储数据、访问权限、子节点引用、节点状态信息,如图:

image-20210621125805584

  • data: znode存储的业务数据信息。
  • ACL:记录客户端对znode节点的访问权限,如IP等。
  • child: 当前节点的子节点引用。
  • stat: 包含Znode节点的状态信息,比如事务id、版本号、时间戳等等。

为了保证高吞吐和低延迟,以及数据的一致性,znode只适合存储非常小的数据,不能超过1M,最好都小于1K。

数据同步

整个集群完成 Leader 选举之后,Learner(Follower 和 Observer 的统称)会向Leader 服务器进行注册。当 Learner 服务器向 Leader 服务器完成注册后,进入数据同步环节。

数据同步流程:(均以消息传递的方式进行)

  1. Learner 向 Learder 注册

  2. 数据同步

  3. 同步确认

Zookeeper 的数据同步通常分为四类

  1. 直接差异化同步(DIFF 同步)

  2. 先回滚再差异化同步(TRUNC+DIFF 同步)

  3. 仅回滚同步(TRUNC 同步)

  4. 全量同步(SNAP 同步)

Zookeeper 是如何保证事务的顺序一致性的

zookeeper 采用了全局递增的事务 id 来标识,所有的 proposal(提议)都在被提出的时候加上了 zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch(时期; 纪元; 世; 新时代)用来标识 leader 周期,如果有新的 leader 产生出来,epoch会自增,低 32 位用来递增计数。

当新产生 proposal 的时候,会依据数据库的两阶段过程,首先会向其他的 server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。

ZK 节点宕机如何处理

Zookeeper 本身也是集群,推荐配置不少于 3 个服务器。Zookeeper 自身也要保证当一个节点宕机时,其他节点会继续提供服务。

  • 如果是一个 Follower 宕机,那还有 2 台服务器提供访问,因为 Zookeeper 上的数据是有多个副本的,数据并不会丢失;

  • 如果是一个 Leader 宕机,Zookeeper 会选举出新的 Leader。

ZK 集群的机制是只要超过半数的节点正常,集群就能正常提供服务。只有在 ZK节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。所以3 个节点的 cluster 可以挂掉 1 个节点(leader 可以得到 2 票>1.5),而2 个节点的 cluster 就不能挂掉任何 1 个节点了(leader 可以得到 1 票<=1)。

Zookeeper 负载均衡和 Nginx 负载均衡区别

zk 的负载均衡是可以调控,nginx 只是能调权重,其他需要可控的都需要自己写插件;但是 nginx 的吞吐量比 zk 大很多,应该说按业务选择用哪种方式。

集群支持动态添加机器吗

动态添加机器其实就是水平扩容,Zookeeper 在这方面不太好。两种方式:

  • 全部重启:关闭所有 Zookeeper 服务,修改配置之后启动,不影响之前客户端的会话。

  • 逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务,这是比较常用的方式。

3.5 版本开始支持动态扩容。

Zookeeper 对节点的 watch监听通知是永久的吗?为什么

不是永久的。官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端,以便通知它们。

dubbo和Zookeeper的关系,什么选择Zookeeper作为注册中心

dubbo的注册中心可以选Zookeeper,memcached,redis等。为什么选择Zookeeper,因为它的功能特性咯~

  • 命名服务:服务提供者向Zookeeper指定节点写入url,完成服务发布。
  • 负载均衡:注册中心的承载能力有限,而Zookeeper集群配合web应用很容易达到负载均衡。
  • zk支持监听事件:特别适合发布/订阅的场景,dubbo的生产者和消费者就类似这场景。
  • 数据模型简单,数据存在内存,可谓高性能。
  • Zookeeper其他特点都可以搬出来讲一下~