重庆怎样网站推广,免费的app软件下载大全,精品课程网站建设开题报告,公司网站做优化欢迎关注公众号#xff08;通过文章导读关注#xff1a;【11来了】#xff09;#xff0c;及时收到 AI 前沿项目工具及新技术的推送#xff01; 在我后台回复 「资料」 可领取编程高频电子书#xff01; 在我后台回复「面试」可领取硬核面试笔记#xff01; 文章导读地址… 欢迎关注公众号通过文章导读关注【11来了】及时收到 AI 前沿项目工具及新技术的推送 在我后台回复 「资料」 可领取编程高频电子书 在我后台回复「面试」可领取硬核面试笔记 文章导读地址点击查看文章导读 感谢你的关注 一篇文章了解 ZooKeeper 底层运行原理
该文章主要说一下 ZooKeeper 底层运行原理以及其中比较核心的功能
CAP 是分布式系统中的基本理论一般只能满足 AP 和 CP常用的注册中心 ZK 和 Nacos
ZooKeeper 符合 CP 选择了一致性而抛弃了部分可用性 因为 ZK 集群中只有 Leader 节点可以写数据如果 Leader 挂了需要重新选举 Leader在这期间 ZK 集群不可用ZK 只有 Leader 可以写所以整个写入操作是 中心化 的Nacos 符合 AP 选择了可用性并且满足最终一致性 并且 Nacos 的设计是去中心化的
并且由于 ZK 的监听机制导致在节点数量较多的时候如果出现大量监听事件的触发会导致 ZK 瞬时流量过大 因此现在将 Zookeeper 作为服务注册中心的公司在减少而是转向使用 Nacos 或自研注册中心
首先说一下 ZooKeeper 用来做什么
ZooKeeper 是一个分布式协调服务提供了一个中心化的服务用于管理和协调分布式应用中的各种配置、信息和事件
那么一般使用 ZooKeeper 中较常用的场景就是 注册中心 、 元数据管理
元数据管理 指对多个分布式服务中都需要用到的基础类型的数据进行管理使用 ZK 管理的好处就是不需要在每一个分布式服务中都进行配置只要在 ZK 中进行配置即可并且配置变更之后所有的分布式服务可以及时收到 数据变更的通知
注册中心 指在那些需要进行 RPC 远程调用时将 RPC 服务注册到 ZK 中去之后需要调用的话可以在 ZK 中查询提供了哪些服务可以进行调用并且可以进行 负载均衡 处理
如下图如果提供了一个 HelloServiceImpl 的 RPC 服务将该服务注册在 ZK 中节点值为该服务的 IP 地址这样调用方在需要使用服务的时候可以拿到该服务的 IP 地址与该服务建立 TCP 连接即可进行通信Dubbo 的注册中心可以使用 ZK 也可以使用 Nacos ZooKeeper 中的核心内容
ZooKeeper 中的核心内容如下
节点类型watcher 监听机制分布式锁集群模式
接下来主要从这几块内容来介绍 ZooKeeper 的运行原理
节点类型
ZK 中的节点类型分为持久节点、临时节点、顺序节点
持久节点创建之后一直存在
临时节点只要客户端断开连接节点就会被删除
顺序节点创建节点时会添加全局递增的序号经典应用场景是 分布式锁 顺序节点既可以是持久节点也可以是临时节点
节点使用应用场景 在 RPC 调用中将提供的 RPC 服务作为临时节点注册在 ZK 中当 RPC 服务提供者与 ZK 断开连接之后该服务在 ZK 中注册的临时节点就会被删除那么我们客户端就可以对该节点添加监听器当发现节点被删除之后就可以感知到对应的服务下线了监听器的内容会在后边说道
ZooKeeper 的监听机制
ZooKeeper 提供了 watcher 监听机制这是 ZK 中最常用的功能因为多个分布式节点之间及时感知到 ZK 数据的变化就是通过 监听机制实现的
ZK 中的 watcher 有以下几个特点
一次性 watcher 被触发之后ZK会将其从客户端的 WatchManager 中删除也会从服务端删除重新注册 watcher 才可以继续下一次的监听串行性 同一 Node 的相同事件类型引发的 watcher 回调方法串行执行也就是只有执行完w atcher 的回调才可以重新生成 watcher 对象进行监听如果回调执行时间太长可能会导致监听事件的丢失因此 ZK 也不适合在 watcher 回调中执行耗时的IO操作
上边说的 watcher 监听是 ZK 中原生的监听机制我们使用 ZK 都是使用它的客户端工具 Curator该客户端工具中也封装了一些丰富的功能来提供给我们进行使用如 分布式锁 、节点监听机制
这里说一下 Curator 提供的节点监听机制 提供了有 3 种类型的监听
NodeCache 监听指定节点单个节点监听PathChilrenCache 监听指定节点的子节点TreeCache 监听指定节点
那么对于 监听机制的使用 这里还是以 RPC 远程服务调用为例如果每一个 RPC 服务提供者都会将自己的 IP 地址注册到对应的节点下那么客户端只需要对 com.zqy.service.impl.HelloServiceImpl 这个节点下的子节点进行监听就可以感知到哪些服务已经下线就不再对该服务进行远程调用即可那么这里就可以使用 PathChildrenCache 来进行监听具体的代码示例这里就不写了只讲原理 分布式锁
ZK 作为分布式协调框架用来作为分布式锁使用从他的设计目的上来讲是比较合适的那么常用的分布式锁还有 Redis 的分布式锁Redisson 客户端框架提供
对于这两种锁到底要如何去选择使用呢
其实使用哪一种都可以两者提供的分布式锁功能都可以满足日常的使用并且使用 Redis 集群和使用 ZK 集群都可以保证较好的锁的可用性
但是两者在 极端情况下也会出现问题 如在 Redis 集群加锁写入主节点之后如果锁的信息未来得及同步到从节点此时主节点宕机就会导致这个锁的信息丢失会出现 重复加锁 的情况在 ZK 集群中如果客户端长时间 GC 导致无法与 ZK 维持心跳ZK 会误认为该客户端下线将该客户端加锁的临时节点删除也会出现 重复加锁 的情况
那么可以看到在 功能性 和 可用性 上两者其实差别都不大具体选用的话可以 根据当前项目使用的技术栈 来进行选择比如当前项目中并没有引入 Redis 依赖只有 ZK 依赖那么直接使用 ZK 的分布式锁完全没有必要去引入 Redis 集群来使用 Redis 的分布式锁因为多一种技术就多一份故障的风险单单为了使用 Redis 分布式锁就去引入 Redis 集群显然小题大做了
ZK 中的分布式锁实现
ZK 的分布式锁就是依靠 临时顺序节点 实现的比如说创建一把名为 lock 的锁那么所有需要加锁的客户端会到该节点下创建 临时顺序节点 只有第一个创建成功的客户端可以拿到锁其他客户端创建的临时顺序节点在后边排序并且对前一个节点进行 监听 当监听到锁释放自己就拿到了锁可以了解一下 Curator 对读写锁出现的羊群效应的解决 ZooKeeper 集群
接下来说一下 ZK 的集群部署ZK 集群中通过分布式一致性协议 ZAB 来保证数据同步的一致性以及 Leader 选举、集群的崩溃恢复接下来会主要 围绕 ZAB 协议 来说一下 ZK 集群相关的核心内容
ZK 集群中有三种角色Leader、Follower、Observer
Leader 执行写操作并且向 Follower 进行同步Follower 从 Leader 同步数据执行读操作不可以执行写操作Observer 只可以执行读操作
ZK 集群其实是适合 写少读多 场景的因为整个集群只有 1 个 Leader 可以写其他节点只可以读那么你可能有疑问Follower 节点用来读数据为什么还需要 Observer 节点呢
这是因为在集群中 Leader 完成写请求是需要经过半数以上的 Follower 都 Ack 之后才可以成功写入的如果集群中 Follower 过多会大大增加 Leader 节点等待 Follower 节点发送 Ack 的时间导致 ZK 集群性能很差因此 ZK 集群部署都是 小集群部署 一般都是 3 台或者 5 台机器
Observer 节点Observer 是只读的、不参与 Leader 选举、也不参与 ZAB 协议同步时过半 Ack 的环节只是单纯的接收数据同步数据达到数据顺序一致性的效果当读并发请求过高时可以 通过不断添加 Observer 节点来分散读请求的压力
ZK 的分布式一致性协议 ZAB 保证数据同步的一致性
ZAB 协议中是采用 2PC 两阶段提交思想完成数据写入的
采用 2PC 两阶段提交思想 的 ZAB 消息广播流程
每一个消息广播的时候都是基于 2PC 的思想先是发起事务提议 Proposal 的广播各个 Follower 返回 Ack当过半的 Follower 都返回 Ack 之后Leader 就发送 Commit 消息到 Follower让大家提交事务
这里的两阶段指的就是发送 Proposal 和 Commit
发起一个事务 Proposal 之前Leader 会分配一个全局唯一递增的事务 idzxid以此来严格保证顺序
Leader 会为每个 Follower 创建一个队列里边存放要发给 Follower 的事务 Proposal保证了一个同步的顺序性
Follower 收到事务 Proposal 之后就立即写入本地磁盘日志中写入成功后数据就不会丢失了之后返回 Ack 给 Leader当过半的 Follower 都返回 AckLeader 推送 Commit 消息给全部 Follower让大家进行事务提交事务提交之后数据就被写入到了 znode也就是内存中 此时数据就可以被用户感知到了 ZK 的 ZAB 保证集群的崩溃恢复
下边将会介绍 ZK 集群 启动 再到 崩溃 再到 恢复 整体的流程
ZK 集启动的时候进入 恢复模式 选举一个 Leader 出来然后 Leader 等待集群中过半的 Follower 跟他进行数据同步只要过半的 Follower 完成数据同步接着就退出恢复模式可以对外提供服务了
此时还没完成同步的 Follower 会自己去跟 Leader 进行数据同步的
之后会进入 消息广播模式 只有 Leader 可以接受写请求但是客户端可以任意连接 Leader 或者 Follower如果客户端连接到 FollowerFollower 就会将写请求转发给 Leader
Leader 收到写请求就把请求同步给所有的 Follower当超过半数的 Follower 都返回了 Ack之后 Leader 先将数据写到自己的 znode 中再给所有的 Follower 发一个 Commit 消息让大家提交这个请求事务Follower 收到 Commit 消息后就会将磁盘中刚刚写入的数据往内存中的 znode 中写之后客户端就可以读取到数据了
如果 Leader 宕机了就会进入 恢复模式 重新选举一个 Leader只要获得了过半的机器的投票就可以成为 Leader
ZK 集群中可以容忍不超过一半的机器宕机就比如说一个集群有 3 台机器那么最多允许 1 台机器宕机剩下的 2 台选举 Leader只要 2 台机器都认可其中一台机器当 Leader也就是超过了集群一半的机器都认可那么就可以选举这台机器作为 Leader
新的 Leader 等待过半的 Follower 跟他同步之后重新进入 消息广播模式
以上就是 ZK 集群恢复崩溃的整个流程了当然我也画了一个流程图更方便观看如下 主要就是分为 3 个阶段 集群启动时恢复模式Leader 选举 数据同步 消息写入时消息广播模式Leader 采用 2PC 的过半写机制给 Follower 进行同步 崩溃恢复恢复模式Leader/Follower 宕机只要剩余机器超过一半就可以选举新的 Leader ZK 集群的性能瓶颈在哪里呢
瓶颈在于 Leader 的 写性能如果 ZK 集群挂掉的话那么很有可能就是 Leader 的写入压力过大这对一个公司的技术平台打击是巨大的因为像 kafka 之类的技术都是强依赖 ZK 的Dubbo ZK 去做服务框架的话当服务实例达到上万甚至几十万时大量服务的上线、注册、心跳的压力达到了每秒几万甚至十万单个 Leader 抗几万的请求还行十几万的话 ZK 单个 Leader 是扛不住这么多的写请求的
想要提升 Leader 的 写性能 目前来说也就是提升部署 ZK 的机器性能了还有一种方式也就是将 dataLogDir 目录挂载的机器上配置 SSD 固态硬盘以此来提升事务日志 写速度 来提升写性能
ZK 集群的 Leader 选举
在 Leader 选举时需要用到以下几个属性
SID 服务器 ID和 myid 一致作为服务器的标识不可以重复
ZXID 事务 ID用来标识一次服务状态的变更ZXID 全局唯一并且递增有 64 位高 32 位时 Leader 的 Epoch低 32 位是递增计数器
Epoch 每个 Leader 任期的代号没有 Leader 时同一轮投票过程中的 Epoch 时相同的每投完一次票就会加 1
当一台机器进入 Leader 选举时当前集群可能处于以下两种状态
集群中已经有一个 Leader
如果已经有 Leader 的情况会被告知当前服务器的 Leader 信息之后进行状态同步即可
集群中确实不存在 Leader
假设 zookeeper 有 5 台服务器SID 分别为 1、2、3、4、5ZXID 分别为 8、8、8、7、7并且 SID 3 的服务器是 Leader
如果某一时刻服务器 3 和 5 出现故障之后服务器 1、2、4 开始 Leader 选举规则如下
1、EPOCH 大的选举为 Leader
2、EPOCH 相同事务 ID 大的选举为 Leader
3、事务 ID 相同SID 大的选举为 Leader
那么对于服务器 1、2、4 来说最终服务器 2 选举为 Leader 这样的选举策略可以保证有 最新数据的节点 可以竞选