掘金 后端 ( ) • 2024-04-18 09:56

ZooKeeper 官网: https://zookeeper.apache.org/

问题背景

在目前的服务架构体系下,单服务架构肯定是无法满足我们的需求的,现在几乎都会采用分布式架构的方式来将服务分散开来,分布式架构优点众多,比如:解耦,可扩展,分散流量等等;但是仔细想想,分布式服务存在一些问题,比如:①一个服务挂了,我怎么让其他服务知道?②多个服务节点同时修改一个共享数据,怎么确保数据同步?,带着这样一些问题,我们想到是不是可以找一个类似'中介'的角色来帮我们处理某些配置数据,那么Zookeeper就此诞生了,Zookeeper负责协调各个服务间的数据同步问题;

Zookeeper是什么

这个问题在上述背景的介绍中已经有一些引入,先看看官方怎么说:

What is ZooKeeper ?

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable. Because of the difficulty of implementing these kinds of services, applications initially usually skimp on them, which make them brittle in the presence of change and difficult to manage. Even when done correctly, different implementations of these services lead to management complexity when the applications are deployed.

我们翻译一下

ZooKeeper是一种集中式服务,用于维护配置信息、命名、提供分布式同步和提供组服务。

所有这些类型的服务都被分布式应用程序以某种形式使用。

每次实现它们时,都有很多工作来修复不可避免的错误和竞争条件。

由于实现这些服务的困难,应用程序最初通常会节省它们,这使得它们在出现变化时显得脆弱,难以管理。

即使操作正确,这些服务的不同实现也会在部署应用程序时导致管理的复杂性。

Zookeeper的优势

  • Zookeeper 数据保存在 内存 中,这意味着 ZooKeeper 可以实现高 吞吐量 低延迟 数字
  • ZooKeeper 分布式 协调服务,能做到高性能、高可用、严格有序的访问

ZooKeeper的数据存储方式

zookeeper的存储在逻辑上的数据结构就是一棵树,没错,可以理解为是linux文件系统的结构,如下图所示

ZooKeeper节点

  • 官方将每一个结点称做Znode
  • Znode 维护一个统计信息结构,其中包括数据更改、ACL 更改和时间戳的版本号,以允许缓存验证和协调更新。每次 znode 的数据更改时,版本号都会增加。例如,每当客户端检索数据时,它也会接收数据的版本。

ACL表示访问控制列表,用于限制谁可以执行哪些操作

特别注意:Znode有临时节点的概念,临时节点在一次会话时创建,会话结束后就会删除

ZooKeeper节点命名

ZooKeeper 提供的命名空间与标准文件系统的命名空间非常相似。名称是用斜杠 (/) 分隔的路径元素序列。ZooKeeper 命名空间中的每个节点都由路径标识。

ZooKeeper的特性

  • 顺序一致性 - 来自客户端的更新将按发送顺序应用。
  • 原子性 - 更新成功或失败。没有部分结果。
  • 单个系统映像 - 无论客户端连接到哪个服务器,客户端都将看到相同的服务视图。也就是说,即使客户端故障转移到具有相同会话的其他服务器,客户端也永远不会看到系统的旧视图。
  • 可靠性 - 应用更新后,它将从该时间起持续存在,直到客户端覆盖更新。
  • 及时性 - 保证系统的客户端视图在特定时间范围内是最新的。

Zookeeper的监听机制

ZooKeeper 支持watch的概念。客户端可以在 znode 上设置监视。当 znode 更改时,将触发并删除监视。当监视被触发时,客户端会收到一个数据包,说 znode 已更改。如果客户端与其中一个 ZooKeeper 服务器之间的连接断开,客户端将收到本地通知

  1. 客户端需要对某个节点注册监听器,当节点删除,修改等操作时会收到通知,监听触发后监听器被删除
  2. 3.6.0 中的新功能: 客户端还可以在 znode 上设置永久的递归监视,这些监视在触发时不会被删除,并且会以递归方式触发已注册的 znode 以及任何子 znode 上的更改。

Zookeeper使用场景

注册中心

说起注册中心一定不会陌生,这是分布式服务中最基本的一个概念,ZooKeeper很明显能提供注册中心的功能,并且由于ZooKeeper的监听机制,当注册的服务信息发生变更时,也能及时的通知注册监听器的服务

master选举机制(选举发生时机有两个:①集群刚刚启动;②Leader节点挂了,重新选举Leader)

ZooKeeper是一个分布式的集群服务,所以必然涉及主从节点,下面是几个核心概念

  • master节点:负责数据的写入
  • follower节点:负责数据的读取,拥有选举投票权
  • observer节点:一般不配置该类型节点,用于读请求过大时作为临时服务来分流,不具备选举权
  • Service id(sid):服务id,每个服务器的唯一编号
  • Zxid:事务id,共64位,每一次的数据变更,事务id会执行+1操作,Zxid越大表明数据越新

一般情况下,我们选择奇数个节点,理由很简单,便于投票选举,当票数大于半数即被选为master 选举机制如下:

假设共有5台机器,sid分别为1,2,3,4,5,初始时zxid均为0,需要得到3票可当选Leader

ZooKeeper 刚刚启动时选举 Leader(此时zxid均为0不考虑)

  1. sid=1的服务启动,此时只有一个服务,1号机将票投给自己,此时1号服务得到1票<3票,选举失败
  2. sid=2的服务启动,1号和2号分别给自己投票,此时1,2号都是1票,接着1号发现2号的sid比自己大,于是1号机重新把票投给了2号,此时1号0票,2号2票,但是均小于3票,所以选举又失败了
  3. sid=3的服务启动,同1,2步骤,投票结束后,1号和2号都是0票,3号为3票,ok,此时3号当选Leader
  4. sid=4的服务启动,其发现sid=3的已经成为Leader了,于是自己主动成为了Follower节点
  5. 同4;

Leader 节点挂了,重新选举Leader

假设此时,用(sid, zxid)表示节点,分别为(1, 2), (2, 10), (3, 10), (4, 3), (5, 4),其中(3, 10)挂掉了;

  1. 此时1,2,4,5号服务首先分别将票投给自己,每个服务均1票
  2. 分别将自己的票投给其他服务,此时如果发现其他服务zxid比自己大,那么将投给自己的那张票投给比自己大的服务,经过投票最终2号服务得到2票,成为了新的Leader,其实就是在原来的基础上多出了zxid的比较而已

分布式锁

例如有3台机器A,B,C同时要去修改Znode(/test)的配置,在访问的同时会创建3个临时节点 假设A的临时节点为(/000), B为(/002),c为(/001)

  1. A发现自己的节点是最小的,于是A拿到锁区修改Znode数据 B发现自己不是最小的,于是监听比自己小1的临时节点C C发现自己不是最小的,于是监听比自己小1的临时节点A
  2. 当A修改完,临时节点删除了,此时C监听到了A的临时节点删除了,并且发现自己是临时节点最小的服务,于是C拿到锁
  3. 同2,B最后拿到锁

总结

如果大家有任何的疑惑或者文章有问题的地方,欢迎在评论区讨论交流!
如果想更加深刻了解Zookeeper,请移步官网进行学习!