Zookeeper




Zookeeper基本架构

ZooKeeper 是分布式系统中的"大管家 "。它本质上是一个分布式协调服务,专门解决分布式环境下的配置管理、名字服务、分布式锁、集群管理等棘手问题。

1. 核心架构:ZAB 协议

ZooKeeper 并没有直接使用 Paxos 或 Raft,而是设计了一套专门的协议:ZAB (ZooKeeper Atomic Broadcast,原子广播协议)

ZAB 协议主要分为两个阶段:

  • 崩溃恢复(选举):当 Leader 挂掉时,集群进入选举模式,选出拥有最新提案(zxid 最大)的节点作为新 Leader。
  • 消息广播(同步):Leader 接收写请求,通过两阶段提交(Propose + Commit)将数据同步给 Follower。只要超过半数节点回复,数据即视为写入成功。

2. 数据模型:类似文件系统的 ZNode

ZooKeeper 的数据存储在内存中,结构像一棵树,每个节点被称为 ZNode

ZNode 有四种类型,这是实现各种功能的基石:

  1. 持久节点 (Persistent):除非手动删除,否则一直存在。
  2. 临时节点 (Ephemeral) :客户端断开连接(Session 失效),节点自动消失。(常用于心跳检测、存活监控)
  3. 持久顺序节点 (Persistent_Sequential):名称后会自动带上递增数字。
  4. 临时顺序节点 (Ephemeral_Sequential)(实现分布式锁的神器)

3. 核心机制:监视器 (Watcher)

这是 ZooKeeper 最强大的功能。

  • 客户端可以监听某个 ZNode 的变化(数据修改、子节点增减)。
  • 当变化发生时,ZooKeeper 会给客户端发送一个一次性的通知。
  • 应用场景:配置中心。你改了数据库密码,所有微服务立刻感知并更新。

4. ZooKeeper 能做什么?(常用场景)

A. 分布式锁:像排队领号一样的逻辑

分布式锁的核心矛盾是:多个进程同时想操作同一个资源(比如修改同一个账户余额),怎么保证只有一个能成功?

ZooKeeper 的做法不是让大家去"抢",而是让大家去**"排队"**。

详细步骤:
  1. 领号(创建临时顺序节点)

    假设大家都要抢一个名为 lock 的锁。客户端 A、B、C 同时在 /locks 路径下创建节点。由于是"顺序节点",ZK 会自动给它们加编号:

    • 客户端 A 创建了 /locks/node-000001
    • 客户端 B 创建了 /locks/node-000002
    • 客户端 C 创建了 /locks/node-000003
  2. 判断自己是否是"最小号"

    每个客户端创建完后,都会看一眼 /locks 目录下的所有子节点。

    • 客户端 A 发现自己是 000001,最小,于是成功获得锁,开始干活。
    • 客户端 B 发现自己是 000002,前面有 A,拿不到锁。
    • 客户端 C 发现自己是 000003,前面有 A 和 B,拿不到锁。
  3. 盯着前一个人(Watcher)

    关键点在这里:没拿到锁的人不会死循环去刷,而是只盯着比自己小的那一个号

    • 客户端 B 监听 node-000001 的消失事件。
    • 客户端 C 监听 node-000002 的消失事件。
  4. 释放与唤醒

    当客户端 A 干完活(或者宕机了),node-000001 消失。此时 ZooKeeper 会通知客户端 B :"喂,你盯着的 01 没了!"。B 发现自己成了最小号,于是获得锁

为什么要用"顺序"和"监听前一个"?

  • 防止惊群效应:如果 1000 个节点同时盯着一个锁,锁一释放,ZK 要同时通知 1000 个人,网络瞬间爆炸。而"盯着前一个"确保了每次只唤醒一个人。
B. 服务注册与发现

像 Dubbo 等框架,Provider 启动时在 ZK 注册一个临时节点。Consumer 监听该目录。如果 Provider 挂了,临时节点消失,Consumer 立刻剔除该地址。

C. 集群选主:抢占"地盘"的逻辑

选主(Master Election)的核心矛盾是:一个集群有多个节点,必须选出一个"老大"来指挥,否则会乱套。

ZooKeeper 的做法是利用 "节点的唯一性""临时节点"

详细步骤:
  1. 抢注(创建同名临时节点)

    集群启动时,所有节点(Node-A, Node-B, Node-C)都会尝试去 ZooKeeper 创建同一个节点:/master

  2. 谁快谁当选

    由于 ZooKeeper 保证了路径的唯一性,同一时间只有一个节点能创建成功

    • 假设 Node-A 抢先创建了 /master,ZK 返回成功。Node-A 成为 Master
    • Node-BNode-C 尝试创建时,ZK 会报错:"节点已存在"。它们就知道已经有老大产生了,于是变成 Follower
  3. 实时监控

    虽然没抢到,但 Node-B 和 Node-C 会对 /master 这个节点设置一个 Watcher(监视器)

  4. 老大挂了怎么办?

    由于 /master临时节点

    • 如果 Node-A 挂了(机器宕机或断网),它与 ZK 的会话中断,/master 节点会被 ZK 自动删除
    • Node-B 和 Node-C 立刻收到通知。它们会再次发起"抢注"操作。
    • 谁先抢到,谁就是下一任 Master。



ZooKeeper 处于 TDSQL 的核心位置

在分布式数据库中,最怕的就是"信息不对称"。例如:

  • SQL 引擎不知道该把请求发给哪个 MySQL 实例。
  • 主库挂了,大家还没达成一致谁是新主库。

ZooKeeper 处于核心位置是因为它提供了 CP(强一致性) 保证。它像一个**"中央公告板"**,所有的关键组件(SQL 引擎、调度管理 OSS、监控采集等)都连接在它身上。只要 ZooKeeper 上的数据变了,所有组件都能立刻感知并达成共识。

ZooKeeper 在TDSQL架构中的主要作用

  • 元数据管理:存储数据库的路由信息(哪个表在哪个分片上)、物理拓扑结构(主从关系、IP 地址)。
  • 配置发布与订阅:当管理员修改了集群参数,通过 ZooKeeper 实时推送到所有 SQL 引擎和 Agent 节点。
  • 存活监控与心跳:Agent 会在 ZooKeeper 上创建临时节点。如果 Agent 挂了,节点消失,ZooKeeper 会立刻通知调度器。
  • 分布式锁:在执行自动化运维操作(如扩容、缩容)时,确保同一时间只有一个任务在运行,防止逻辑冲突。

具体场景举例:主从切换(故障自愈)

这是 TDSQL 最依赖 ZooKeeper 的场景之一。

场景描述

假设 Set1 中的 主库(Agent+MySQL) 突然机房断电宕机了。

执行过程
  1. 节点消失 :主库 Agent 在 ZooKeeper 上维护的是一个临时节点。主库宕机后,Session 断开,该节点自动删除。
  2. 触发警报OSS (Schedule Manager) 一直监听(Watch)着这个路径。发现主库节点没了,立刻意识到:"主库挂了!"
  3. 选主决策 :OSS 从 ZooKeeper 中读取 Set1 的备库信息,选出一个数据最全的从库
  4. 更新真相:OSS 修改 ZooKeeper 里的元数据,将该从库标记为"新主库"。
  5. 路由感知 :前端的 SQL 引擎 也监听着 ZooKeeper。它发现"真相"变了,立刻更新自己的路由表,将后续的所有写请求转发给新的主库 IP。
结果

整个过程在秒级完成。对于 APP 来说,只感觉到了一瞬间的闪断,而底层的切换逻辑完全由 ZooKeeper 配合 OSS 自动完成。




为什么要用Zookeeper

ZooKeeper 之所以能成为分布式架构(如你所见的 TDSQL)中的核心,是因为它在设计上提供了一套极其严苛的一致性保证独特的交互机制

ZooKeeper核心特性

ZooKeeper 的设计目标是将复杂的、容易出错的分布式协调过程封装起来,只给用户提供简单易用的接口。其核心特性可以总结为以下几点:

1. 强一致性保证 (CP 属性)
  • 顺序一致性:来自同一个客户端的更新将按其发送顺序依次应用。
  • 原子性:更新操作要么成功,要么失败,没有中间状态。
  • 单一视图:无论客户端连接到集群中的哪个服务器,看到的服务端数据模型都是一致的。
2. 独特的节点机制 (ZNode)

ZooKeeper 的数据结构类似文件系统,但它的节点(ZNode)具有特殊属性:

  • 临时节点 (Ephemeral) :生命周期与客户端会话(Session)绑定。如果客户端宕机,节点自动删除。这是实现故障检测存活监控的关键。
  • 顺序节点 (Sequential) :创建时自动在名后追加递增序列号。这是实现分布式锁分布式队列的基础。
3. 事件监听机制 (Watcher)
  • 这是 ZooKeeper 最具魅力的特性。客户端可以对某个节点注册监听器,当节点数据变化或子节点增减时,ZooKeeper 会主动推送通知。
  • 意义:它改变了传统的"轮训(Polling)"模式,大大降低了网络开销和响应延迟。

ZooKeeper解决的痛点

在分布式系统中,如果没有一个像 ZooKeeper 这样的"真相来源",会产生以下几个致命问题:

A. 解决"谁是老大"的问题 (Leader Election)

在 TDSQL 或 Kafka 集群中,必须选出一个主节点来负责调度。

  • 不用 ZK:节点间需要通过复杂的相互投票,且极易出现"脑裂"(即两个节点都认为自己是主节点)。
  • 用 ZK :大家抢着去创建一个名为 /master 的临时节点,谁创建成功谁就是老大。由于 ZK 保证了节点的唯一性,绝不会出现两个主节点。
B. 解决"数据在哪"的问题 (Metadata Management)
  • 分布式数据库有成千上万个分片,SQL 引擎需要实时知道每个分片在哪个 IP 上。
  • 场景 :当发生扩容或迁移时,OSS 组件只需更新 ZooKeeper 里的路由表,所有 SQL 引擎通过 Watcher 瞬间就能更新本地缓存。
C. 解决"步调一致"的问题 (Distributed Barriers/Locks)
  • 当多个进程需要同时完成某项任务,或者需要竞争同一份资源时。
  • 场景 :防止多个管理后台同时对同一个数据库实例下发重启指令。通过 ZooKeeper 实现的分布式锁可以确保操作的互斥性

相关推荐
布吉岛的石头2 小时前
分库分表实战:Sharding-JDBC 快速落地
分布式·mysql
渔民小镇7 小时前
4 行代码接入 Spring —— ionet 的生态融合之道
java·服务器·分布式·游戏
苍煜8 小时前
Kafka vs RocketMQ 生产环境选型指南
分布式·kafka·rocketmq
雨辰AI9 小时前
SpringBoot3 + 人大金仓 V9 全栈日志实战:Logback + Loki + Filebeat 构建统一日志平台
java·数据库·后端·云原生·eureka·logback·政务
m0_716255009 小时前
第二部分 电商离线数仓 全套项目代码(可直接在你伪分布式 Hive 运行)
hive·hadoop·分布式
旷世奇才李先生9 小时前
Spring Cloud Alibaba 2026微服务全栈实战:服务治理\+流量控制\+分布式事务
分布式·微服务·架构
Amy187021118239 小时前
虚拟电厂为什么必须“牵手”微电网?答案全在这里
分布式·安全·能源
梵得儿SHI11 小时前
(第三篇)Spring AI 架构设计与优化:容器化与云原生部署,基于 K8s 的 AI 应用全生命周期管理
java·ci/cd·docker·云原生·kubernetes·容器化·spring ai
AI攻城狮11 小时前
AI不是泡沫,但让机器人去当和尚是闹剧
云原生