一文弄懂 ZooKeeper

Posted mn_kw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文弄懂 ZooKeeper相关的知识,希望对你有一定的参考价值。

一文弄懂 ZooKeeper

1. ZooKeeper 功能以及使用场景

1.1 ZooKeeper 功能

  • 分布式锁
分布式锁:运用于分布式的 Java 业务系统中
目前常用分布式锁实现方式:Redis 实现的分布式锁, ZooKeeper 实现分布式锁
  • 元数据管理
元数据管理:Kafka、Canal,本身都是分布式架构,分布式集群在运行,本身他需要一个地方集中式的存储和管理分布式集群的核心元数据,所以他们都选择把核心元数据放在 ZooKeeper 中
  • 分布式协调通知
分布式协调:如果有人对 ZooKeeper 中的数据做了变更,然后 ZooKeeper 会反过来去通知其他监听这个数据的人,告诉别人这个数据变更了,kafka 有多个 Broker,多个 Broker 会竞争成为一个 Controller 的角色
如果作为 Controller 的 Broker 挂掉了,此时他在 ZooKeeper 里注册的一个节点会消失,其他 Broker 瞬间会被 ZooKeeper 反向通知这个事情,继续竞争成为新的 Controller
这个就是非常经典的一个分布式协调的场景,有一个数据,一个 Broker 注册了一个数据,其他 Broker 监听这个数据
  • HA master 的选举
Master 选举 -> HA 架构
HDFS,NameNode HA 架构,部署主备两个 NameNode,只有一个人可以通过 ZooKeeper 选举成为 Master,另外一个 B Ack up
Canal 的 HA 架构也是同样原理

1.2 ZooKeeper 使用场景

  • 第一类:分布式 Java 业务系统
分布式 Java 业务系统中, ZooKeeper ,用的比较少,主要使用 ZooKeeper 做分布式锁的功能,不过很多人会选择用 Redis 分布式锁
  • 第二类:开源的分布式系统
1. Dubbo: ZooKeeper  作为注册中心,分布式集群的集中式元数据存储
2. HBase:分布式集群的集中式元数据存储
3. HDFS:Master 选举实现HA架构
4. Kafka:分布式集群的集中式元数据存储,分布式协调和通知
5. Canal:分布式集群的集中式元数据存储,Master 选举实现 HA 架构
  • 第三类:自研的分布式系统
NameNode 的 HA 架构,仿照 HDFS 的 NameNode 的 HA 架构,做主备两个 NameNode,进行数据同步,然后自动基于 ZooKeeper 进行热切换,如果你自己研发类似的一些分布式系统,都可以考虑,你是否需要一个地方集中式存储分布式集群的元数据?是否需要一个东西辅助你进行Master 选举实现HA架构?进行分布式协调通知?
如果你在自研分布式系统的时候,有类似的需求,那么就可以考虑引入 ZooKeeper 来满足你的需求

2. ZooKeeper 架构设计特性及数据模型

2.1. ZooKeeper 的架构设计特点

1. 集群化部署:3~5台机器组成一个集群,每台机器都在内存保存了 ZooKeeper 的全部数据,机器之间互相通信同步数据,客户端连接任何一台机器都可以
2. 树形结构的数据模型:Znode ,树形结构,数据模型简单,纯内存保存
数据结构就跟我们的文件系统是类似的,是有层级关系的树形的文件系统的数据结构
Znode 可以认为是一个节点而已
create /usr/local/uid
create /usr/local/test_file
3. 顺序写:集群中只有一台机器可以写,所有机器都可以读,所有写请求都会分配一个 ZooKeeper 集群全局的唯一递增编号, Zxid ,保证各种客户端发起的写请求都是有顺序的
4. 数据一致性:任何一台 ZooKeeper 机器收到了写请求之后都会同步给其他机器,保证数据的强一致,你连接到任何一台 ZooKeeper 机器看到的数据都是一致的
5. 高性能:每台 ZooKeeper 机器都在内存维护数据,所以 ZooKeeper 集群绝对是高并发高性能的,如果你让 ZooKeeper 部署在高配置物理机上,一个3台机器的 ZooKeeper 集群抗下每秒几万请求没有问题
6. 高可用:哪怕集群中挂掉不超过一半的机器,都能保证可用,数据不会丢失,3台机器可以挂1台,5台机器可以挂2台
7. 高并发:高性能决定的,只要基于纯内存数据结构来处理,并发能力是很高的,只有一台机器进行写,但是高配置的物理机,比如16核32G,写入几万 QPS,读,所有机器都可以读,3台机器的话,起码可以支撑十几万 QPS

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7AKkekAH-1674990266207)(https://lexiangla.com/assets/a3abb9409faf11ed8a7d4a5febc389d1)]

2.2. ZooKeeper 的集群节点三种角色

1. Leader :集群启动自动选举一个 Leader 出来,只有 Leader 是可以写的
2.  Follower : Follower  是只能同步数据和提供数据的读取, Leader 挂了, Follower  可以继续选举出来 Leader 
3.  Observer : Observer  也只能读但是 Observer 不参与选举

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RIJK22Yw-1674990266208)(https://lexiangla.com/assets/340317549fb011ed9006a6b09885f4d9)]

2.3 客户端与 ZooKeeper 之间的长连接和会话

 ZooKeeper 集群启动之后,自己分配好角色,然后客户端就会跟 ZooKeeper 建立连接,是TCP长连接
也就建立了一个会话,就是 Session,可以通过心跳感知到会话是否存在,有一个 SessionTimeout,意思就是如果连接断开了,只要客户端在指定时间内重新连接 ZooKeeper 一台机器,就能继续保持 Session,否则 Session 就超时了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cka9ka8d-1674990266208)(https://lexiangla.com/assets/3a96bc109fb011edbd80aabe39436f7a)]

2.3. ZooKeeper 的数据模型

  • Znode 节点类型
核心数据模型就是 Znode 树,平时我们往 ZooKeeper 写数据就是创建树形结构的 Znode,里面可以写入值,就这数据模型,都在 ZooKeeper 内存里存放
有两种节点,持久节点和临时节点,
1. 持久性节点:持久节点就是哪怕客户端断开连接,一直存在
2. 临时节点:临时节点,就是只要客户端断开连接,节点就没了
  • 节点使用
顺序节点,就是创建节点的时候自增加全局递增的序号
1. ZooKeeper 锁的源码中,Curator 框架, ZooKeeper  分布式锁的实现,在里面就是基于 ZooKeeper 的临时顺序节点来实现的,加锁的时候,是创建一个临时顺序节点, ZooKeeper 会自动给你的临时节点加上一个后缀,全局递增的编号,如果你客户端断开连接了,就自动销毁这个你加的锁,此时会感知到,就会尝试去加锁
2. 如果是做元数据存储,肯定是持久节点
3. 如果是做一些分布式协调和通知,很多时候是用临时节点,比如我创建一个临时节点,别人来监听这个节点的变化,如果我断开连接了,临时节点消失,此时人家会感知到,就会来做点别的事情

2.4. ZooKeeper Watcher 监听回调机制

 ZooKeeper  最核心的机制,就是你一个客户端可以对 Znode 进行 Watcher 监听,然后 Znode 改变的时候回调通知你的这个客户端,这个是非常有用的一个功能,在分布式系统的协调中是很有必要的
1. 支持写和查:只能实现元数据存储,Master 选举,部分功能
2. 分布式系统的协调需求:分布式架构中的系统A监听一个数据的变化,如果分布式架构中的系统B更新了那个数据节点, ZooKeeper  反过来通知系统A这个数据的变化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rRSFnuyY-1674990266209)(https://lexiangla.com/assets/7a9b95ec9fb011ed83e83ed3894aabc3)]

3. ZooKeeper 集群 ZAB 协议

3.1 ZooKeeper 集群间进行数据一致性同步保证协议

 ZAB  协议全称: ZooKeeper  Atomic Broadcas( ZooKeeper  原子广播协议)主要是基于 Paxos 协议的一个改进
 ZAB  协议是为分布式协调服务 ZooKeeper 专门设计的一种支持 崩溃恢复 和 原子广播 协议,基于该协议, ZooKeeper  实现了一种 主备模式 的系统架构来保持集群中各个副本之间数据一致性。

3.2. ZAB 的核心思想之主从同步机制和崩溃恢复机制

1. 协议的本质而言,划分集群角色,主从架构, Leader 和  Follower  两种角色
2. 只有 Leader 可以接受写操作, Leader 和  Follower  都可以读, Leader 收到事务请求,转换为事务  Proposal (提议)同步给所有的  Follower ,超过半数的  Follower  都说收到事务 Proposal 了, Leader 再给所有的  Follower  发一个 Commit 消息,让所有 Follower  提交一个事务,而且如果 Leader 崩溃了,要重新选举 Leader 保证继续运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JNghaxRY-1674990266209)(https://lexiangla.com/assets/b18d6c9c9fb011ed9f4bcadc82f49205)]

3.3. 从 ZooKeeper 集群启动到数据同步再到崩溃恢复分析 ZAB 协议流程

1. ZooKeeper 集群启动的时候,进入恢复模式,选举一个 Leader 出来,然后 Leader 等待集群中过半的 Follower 跟他进行数据同步,只要过半 Follower 完成数据同步,接着就退出恢复模式,可以对外提供服务了
2. 只要有超过一半的机器,认可你是 Leader ,你就可以被选举为 Leader ,3台机器组成了一个 ZooKeeper 集群,启动的时候,只要有2台机器认可一个人是 Leader ,那么他就可以成为 Leader 了
3. 当然还没完成同步的 Follower 会自己去跟 Leader 进行数据同步的,此时会进入消息广播模式,只有 Leader 可以接受写请求,但是客户端可以随便连接 Leader 或者 Follower ,如果客户端连接到 Follower , Follower 会把写请求转发给 Leader 
4. Leader 收到写请求,就把请求同步给所有的 Follower 
5. 过半 Follower 都说收到了,就再发Commit给所有的 Follower ,让大家提交这个请求事务
6. 如果突然 Leader 宕机了,会进入恢复模式,重新选举一个 Leader ,只要过半的机器都承认你是 Leader ,就可以选举出来一个 Leader ,所以 ZooKeeper 很重要的一点是主要宕机的机器数量小于一半,他就可以正常工作,因为主要有过半的机器存活下来,就可以选举新的 Leader ,新 Leader 重新等待过半 Follower 跟他同步,完了重新进入消息广播模式

3.4. ZooKeeper 采用了 2PC 两阶段提交思想的 ZAB 消息广播流程

1. 每一个消息广播的时候,都是2PC思想走的
2. 先是发起事务 Proposal 的广播,就是事务提议,仅仅只是个提议而已
3. 发起一个事务 Proposal 之前, Leader 会分配一个全局唯一递增的事务id, Zxid ,通过这个可以严格保证顺序
4. Leader 会为每个 Follower 创建一个队列,里面放入要发送给 Follower 的事务 Proposal ,这是保证了一个同步的顺序性
5. 每个 Follower 收到一个事务 Proposal 之后,就需要立即写入本地磁盘日志中,写入成功之后就可以保证数据不会丢失了,然后返回一个 Ack 给 Leader 
6. 然后过半 Follower 都返回了 Ack , Leader 推送Commit消息给全部 Follower ,
7. Leader 自己也会进行Commit操作
8. Commit之后,就意味这个数据可以被读取到了

3.5. ZooKeeper 到底是强一致性还是最终一致性?

  • 强一致性介绍
强一致性:只要写入一条数据,立马无论从 ZooKeeper 哪台机器上都可以立马读到这条数据,强一致性,你的写入操作卡住,直到 Leader 和全部 Follower 都进行了Commit之后,才能让写入操作返回,认为写入成功了
此时只要写入成功,无论你从哪个 ZooKeeper 机器查询,都是能查到的,强一致性,明显, ZAB 协议机制, ZooKeeper 一定不是强一致性
  • 最终一致性介绍
最终一致性:写入一条数据,方法返回,告诉你写入成功了,此时有可能你立马去其他 ZooKeeper 机器上查是查不到的,短暂时间是不一致的,但是过一会儿,最终一定会让其他机器同步这条数据,最终一定是可以查到的
  • ZooKeeper 是强一致性还是最终一致性
研究了 ZooKeeper 的 ZAB 协议之后,你会发现,其实过半 Follower 对事务 Proposal 返回 Ack ,就会发送Commit给所有 Follower 了,只要 Follower 或者 Leader 进行了Commit,这个数据就会被客户端读取到了
那么有没有可能,此时有的 Follower 已经Commit了,但是有的 Follower 还没有Commit?绝对会的,所以有可能其实某个客户端连接到 Follower01,可以读取到刚Commit的数据,但是有的客户端连接到 Follower02在这个时间还没法读取到
所以 ZooKeeper 不是强一致的,不是说 Leader 必须保证一条数据被全部 Follower 都Commit了才会让你读取到数据,而是过程中可能你会在不同的 Follower 上读取到不一致的数据,但是最终一定会全部Commit后一致,让你读到一致的数据的
  • ZooKeeper 官方给自己的定义:顺序一致性
因此 ZooKeeper 是最终一致性的,但是其实他比最终一致性更好一点,出去要说是顺序一致性的,因为 Leader 一定会保证所有的 Proposal 同步到 Follower 上都是按照顺序来走的,起码顺序不会乱
但是全部 Follower 的数据一致确实是最终才能实现一致的
如果要求强一致性,可以手动调用 ZooKeeper 的sync()操作

4. ZooKeeper 适用场景

4.1. ZooKeeper 适用读多写少场景

  • 先看下 Eureka 架构
peer-to-peer架构(对等架构)
比如 Eureka ,小集群部署,每个节点收到的注册、心跳所有的信息,都必须向其他节点都进行同步,有很大的问题,他在进行同步的时候,采取的是完全的一个异步同步的机制,不管什么2PC,异步慢慢同步就可以了,时效性是很差, Eureka ,这个技术不适合大公司,大厂的场景去使用
  • 再看 ZooKeeper 为什么只适用小型部署
因为假设你有1个 Leader + 20个 Follower ,21台机器,这是不靠谱的,因为 Follower 要参与到 ZAB 的写请求过半 Ack 里去
如果你有20个 Follower ,一个写请求出去,要起码等待10台以上的 Follower 返回 Ack ,才能发送Commit,才能告诉你写请求成功了,性能是极差
所以 ZooKeeper 的这个 ZAB 协议就决定了一般其实就是1个 Leader + 2个 Follower 的小集群就够了,写请求是无法扩展的,读请求如果量大,可以加 Observer 机器,最终就是适合读多写少的场景
  • ZooKeeper 的 Observer 节点用来扩展读请求
1.  Observer 节点是不参与 Leader 选举的,他也不参与 ZAB 协议同步时候的过半 Follower   Ack 的那个环节,他只是单纯的接收数据,同步数据,可能数据存在一定的不一致的问题,但是是只读的

2. ZooKeeper 集群无论多少台机器,只能是一个 Leader 进行写,单机写入最多每秒上万QPS,这是没法扩展的,所以 ZooKeeper 是适合写少的场景

3. 但是读呢? Follower 起码有2个或者4个,读你起码可以有每秒几万QPS,没问题,那如果读请求更多呢?此时可以引入 Observer 节点,它就只是同步数据,提供读服务,可以无限的扩展机器

4.2. ZooKeeper 错误使用方式

  • 不要乱用 ZooKeeper
这也就让大家知道了,很多互联网公司里,不少系统使用 ZooKeeper ,以为 ZooKeeper 可以承载高并发写,结果每秒几万写请求下去, ZooKeeper 的 Leader 机器直接可能就挂掉了,扛不住那么大的请求量, ZooKeeper 一旦挂掉,连带的kafka等系统会全部挂掉
  • ZooKeeper 大量写入,集群会挂掉
 Leader 写入压力过大, 最终导致集群挂掉,对公司的技术平台是有重大打击,hbase、kafka之类的一些技术都是强依赖 ZooKeeper 的,Dubbo + ZooKeeper 去做服务框架的话,有大量服务实例的时候
大量的服务的上线、注册、心跳的压力,达到了每秒几万,甚至上十万, ZooKeeper 的单个 Leader 写入是扛不住那么大的压力的
一般适合写比较少
读比较多, Observer 节点去线性扩展他的高并发读的能力

5. ZooKeeper 特性的总结

1. 集群模式部署
一般奇数节点,因为你5台机器可以挂2台,6台机器也是挂2台,不能超过一半的机器挂掉,所以5台和6台效果一致,那奇数节点可以减少机器开销,小集群部署,读多写少
2. 主从架构: Leader 、 Follower 、 Observer (一般刚开始没必要用)
3. 内存数据模型:Znode,多种节点类型
4. 客户端跟 ZooKeeper 进行长连接,TCP,心跳,维持 Session
5.  Zxid ,高32位,低32位
6.  ZAB 协议,2PC,过半 Ack + 磁盘日志写,Commit + 写内存数据结构
7. 支持Watcher机制,监听回调通知
8. 顺序一致性:消息按顺序同步,但是最终才会一致,不是强一致
9. 高性能,2PC中的过半写机制,纯内存的数据结构,Znode(纯内存)
10. 高可用, Follower 宕机没影响, Leader 宕机有数据不一致问题,新选举的 Leader 会自动处理,正常运行,但是在恢复模式期间,可能有一小段时间是没法写入 ZooKeeper 的
11. 高并发,单机 Leader 写, Observer 可以线性扩展读QPS

以上是关于一文弄懂 ZooKeeper的主要内容,如果未能解决你的问题,请参考以下文章

技术分享 MySQL:一文弄懂时区&time_zone

一文弄懂 ZooKeeper

一文带你弄懂 CDN 技术的原理

一文弄懂Spring事务相关知识

一文弄懂数组的和

探秘react,一文弄懂react的基本使用和高级特性