分布式系统zookeeper

CAP 理论

是分布式系统的核心理论之一

1. CAP 的三个特性

  • 一致性(Consistency):所有节点同时看到相同的数据,即更新操作后,所有节点的数据是一致的。
  • 可用性(Availability):任何合法请求都能在合理时间内得到响应(不保证数据最新,但服务必须可用)。
  • 分区容错性(Partition Tolerance):当网络分区(部分节点之间通信中断)发生时,系统仍能继续运行。

2. CAP 的核心结论

在分布式系统中,网络分区是无法避免的(必须满足 P),因此只能在 “C” 和 “A” 中二选一:

  • CP 模式:优先保证一致性和分区容错性,牺牲可用性。例:ZooKeeper(分布式协调场景,需强一致,网络分区时可能拒绝请求)。
  • AP 模式:优先保证可用性和分区容错性,牺牲强一致性(允许最终一致)。例:Eureka(服务注册中心,网络分区时仍能提供服务,数据后续同步)。

3. 注意点

  • CAP 理论是针对 “分布式系统” 的,单机系统不存在网络分区,可同时满足 CAP。
  • 实际系统通常是 “CP” 或 “AP” 的折中(如 MySQL 主从复制是 “最终一致的 AP”,但可通过同步复制实现 “CP”)。

zookeeper 保证的是 CP,对比 spring cloud 系统中的注册中心 eureka实现的是AP 模式。

BASE 理论

BASE 理论是对 CAP 理论中 延伸和补充,是大规模分布式系统(如微服务、电商平台)的设计指导思想,核心是放弃强一致性,追求最终一致性

它的全称是:

  • Basically Available(基本可用)
  • Soft state(软状态)
  • Eventually consistent(最终一致性)

1. 三大核心特性

(1)Basically Available(基本可用)

分布式系统在出现故障或分区时,允许损失部分可用性,但核心功能仍能正常提供服务。

  • 与 CAP 中的 A(可用性) 区别:CAP 的可用性要求 “任何请求都能得到响应”,而 BASE 的基本可用允许 “有限度的降级”。
  • 示例:电商大促时,非核心功能(如商品历史评价)暂时不可用,优先保障下单、支付核心流程;Eureka 网络分区时,节点独立提供注册 / 发现服务,不保证集群数据完全一致,但服务不中断。

(2)Soft state(软状态)

允许系统存在中间状态,这个状态不会影响系统整体可用性,且中间状态会自动在一定时间内收敛到一致状态。

  • “软状态” 的核心是不强制要求节点数据实时一致,允许数据在同步过程中存在延迟。
  • 示例:Redis 主从复制中,主节点写入数据后,从节点可能存在短暂的数据滞后,这个滞后状态就是 “软状态”;消息队列中,消息从生产者发送到消费者的过程中,存在 “已发送但未消费” 的中间状态。

(3)Eventually consistent(最终一致性)

系统中的所有节点数据,在没有新的更新操作的情况下,经过一段时间的同步后,最终会达到一致状态。

  • 最终一致性不保证 “实时一致”,但保证 “数据最终会对齐”,同步时间取决于网络延迟、重试机制等。
  • 常见的最终一致性类型:因果一致性:有因果关系的操作必须保证顺序一致(如先下单后支付,不能颠倒);会话一致性:同一个用户会话内,操作的结果是一致的;时间窗口一致性:数据在指定时间窗口内达到一致。

2.四种类型

1.强一致性:又称线性一致性(linearizability )

1.任意时刻,所有节点中的数据是一样的、

2.一个集群需要对外部提供强一致性,所以只要集群内部某一台服务器的数据发生了改变,那么就需要等待集群内其他服务器的数据同步完成后,才能正常的对外提供服务

3.保证了强一致性,务必会损耗可用性

2.弱一致性:

1.系统中的某个数据被更新后,后续对该数据的读取操作可能得到更新后的值,也可能是更改前的值。

2.即使过了不一致时间窗口,后续的读取也不一定能保证一致。

3.最终一致性:

1.弱一致性的特殊形式,不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。

2.存储系统保证在没有新的更新的条件下,最终所有的访问都是最后更新的值

4.顺序一致性:

1.任何一次读都能读到某个数据的最近一次写的数据。

2.对其他节点之前的修改是可见(已同步)且确定的,并且新的写入建立在已经达成同步的基础上。

Zookeeper写入是强一致性,读取是顺序一致性。

Zookeeper介绍

官方:https://zookeeper.apache.org/

1.Apache ZooKeeper 是一个开源的分布式协调服务框架

专为分布式系统提供高效、可靠的协调能力,其设计目标是解决分布式集中场景下的一致性、同步、配置管理等核心问题。

图中的 “ZooKeeper” 作为中间协调者,连接用户(Actor)和后端服务(Service 集群),体现了 ZooKeeper 在分布式系统中“管理服务、同步信息” 的核心功能。

ZooKeeper本质上是一个分布式的小文件存储系统(Zookeeper=文件系统+监听机制)。提供基于类似于文件系统的目录树方式的数据存储,并且可以对树中的节点进行有效管理,从而用来维护和监控存储的数据的状态变化。

ZooKeeper 的设计模式围绕 “分布式协调” 的核心目标,主要采用以下几种典型设计模式:

2.ZooKeeper 最核心的设计模式

1. 观察者模式(Observer Pattern)

这是 ZooKeeper 最核心的设计模式,对应其监听机制

  • 角色划分:被观察者:ZooKeeper 中的 ZNode 节点;观察者:注册了监听器的客户端。
  • 工作逻辑:客户端向 ZNode 注册监听器后,若节点数据 / 状态发生变化,ZooKeeper 会主动向客户端推送事件(如节点创建、数据修改),客户端收到通知后执行相应逻辑(如更新本地配置、重新竞争锁)。
  • 作用:实现 “数据变化驱动业务逻辑”,支撑分布式配置刷新、服务上下线感知等场景。

2. 发布 - 订阅模式(Publish-Subscribe Pattern)

是观察者模式的延伸,对应 ZooKeeper 的数据分发能力

  • 角色划分:发布者:更新 ZNode 数据的客户端;订阅者:监听 ZNode 的多个客户端。
  • 工作逻辑:发布者修改 ZNode 数据后,ZooKeeper 会将变更同步给所有订阅该节点的客户端,实现 “一处更新、多处感知”。
  • 作用:支撑分布式消息通知、配置统一推送等场景。

3. 领导者选举模式(Leader Election Pattern)

对应 ZooKeeper 集群自身的主从架构,也支撑上层业务的选主需求:

  • 工作逻辑:ZooKeeper 集群启动时,通过 ZAB 协议选举 Leader 节点(处理写请求、同步数据),Follower 节点则处理读请求、参与投票;业务层可基于 ZooKeeper 的临时顺序节点,让多个客户端竞争创建节点,序号最小的节点对应 “领导者”,实现分布式选主。
  • 作用:保证集群自身的高可用,同时支撑业务的主节点选举(如分布式任务调度的主节点)。

4. 享元模式(Flyweight Pattern)

对应 ZooKeeper 的会话复用与资源共享

  • 工作逻辑:ZooKeeper 客户端与服务端建立的会话(Session)会被复用,避免频繁创建连接;同时,多个客户端可共享同一 ZNode 的监听器逻辑(如同一配置节点的多个订阅者,共享 ZooKeeper 的事件推送能力)。
  • 作用:减少资源开销,提升集群的并发处理能力。

这些模式的组合,让 ZooKeeper 既实现了自身集群的高可用,又能高效支撑分布式系统的各类协调场景。

3.ZooKeeper数据结构

每个点称做一个 ZNode,像树一样。ZooKeeper的数据模型是层次模型

ZooKeeper的层次模型称作Data Tree,Data Tree的每个节点叫作Znode。不同于文件系统,每个节点都可以保存数据,每一个 ZNode 默认能够存储 1MB 的数据,每个 ZNode都可以通过其路径唯一标识,每个节点都有一个版本(version),版本从0开始计数。

4.ZooKeeper 的节点(ZNode)类型

主要分为4 类核心类型,其区别在于 “生命周期” 和 “是否自动生成序号”,对应不同的分布式场景:

1. 持久节点(Persistent Node)

  • 生命周期:一旦创建,永久存在(除非主动执行delete命令删除)。
  • 核心特点:不受客户端会话影响,会话断开后节点仍保留。
  • 典型用途:存储持久化的配置信息、分布式资源的统一命名(如/app/name)。

2. 临时节点(Ephemeral Node)

  • 生命周期:与客户端会话绑定,会话断开(主动关闭 / 超时)后,节点自动删除。
  • 核心特点:不能创建子节点(ZooKeeper 限制临时节点无下级节点)。
  • 典型用途:服务注册(如/services/serviceA/192.168.1.100:8080,服务下线后节点自动清理)、临时状态标识。

3. 持久顺序节点(Persistent Sequential Node)

  • 生命周期:同 “持久节点”(永久存在)。
  • 核心特点:创建时,ZooKeeper 会在节点名后自动追加递增序号(如/queue/task0000000001),保证同一父节点下的节点唯一且有序。
  • 典型用途:分布式队列(按序号顺序消费任务)、全局唯一 ID 生成。

4. 临时顺序节点(Ephemeral Sequential Node)

  • 生命周期:同 “临时节点”(会话断开后自动删除)。
  • 核心特点:节点名后自动追加递增序号,兼具 “临时” 和 “顺序” 特性。
  • 典型用途:分布式锁(通过序号竞争锁,会话断开后锁自动释放)、分布式选主(序号最小的节点作为主节点)。

5. Container节点 (3.5.3版本新增)

6. TTL节点: 带过期时间节点,

默认禁用,需要在zoo.cfg中添加extendedTypesEnabled=true 开启。 注意:ttl不能用于临时节点

下载的教程直接豆包看就行,这是启动了服务端和客户端的。

从界面日志可以判断:ZooKeeper 已经成功启动

关键依据:

  1. 服务端日志显示binding to port 0.0.0.0/0.0.0.0:2181,说明服务端已在 2181 端口监听连接;
  2. 客户端日志显示[zk: localhost:2181(CONNECTED) 0],代表客户端已成功连接到服务端,处于可用状态。

1. 节点操作(最核心)

查看根节点下的内容ls /

1. 命令执行情况

  • 输入的ls /命令已执行,返回结果为[zookeeper],说明根路径/下默认存在一个名为zookeeper的系统节点(ZooKeeper 自身的管理节点)。

2. 该节点的作用

/zookeeper是 ZooKeeper 的内置节点,主要用于存储系统级数据,例如:

  • 存储 ACL(权限控制)相关信息;
  • 记录集群的元数据等,通常不建议用户直接修改该节点。

创建节点(临时 / 持久)

持久节点(服务重启后仍存在):create /test "testdata"

create /test "testdata":在根节点下创建名为/test的节点,并写入数据testdata,执行结果Created /test表示操作成功。

执行ls /后,返回了根节点下的子节点test,说明之前创建的/test节点已存在于根路径下。

create -e /tempnode "tempdata"

  • 参数-e表示创建临时节点(临时节点会在客户端会话结束后自动删除);
  • 执行结果Created /tempnode表示成功在根节点下创建了临时节点/tempnode,并写入数据tempdata
  • 执行ls /后,返回[tempnode, test, zookeeper],说明根路径/下已存在 3 个节点:

    • tempnode:你之前创建的临时节点;
    • test:你之前创建的持久节点;
    • zookeeper:ZooKeeper 默认系统节点。

    查看节点数据:get /test

    修改节点数据set /test "newdata"

    删除节点delete /test

    节点状态信息

    get -s /test

    5.监听通知(watcher)机制

    1. 核心逻辑

    • 触发规则:客户端对节点注册 Watcher 后,当节点发生指定变更(如数据修改、子节点增删),ZooKeeper 会向客户端推送事件通知。
    • 单次生效:Watcher 是 “一次性” 的,收到通知后若需继续监听,需重新注册。

    2. 常用监听场景及实操

    节点数据变更get -s -w /test 数据被修改 / 删除时触发

  • 通过-s获取了/test节点的完整状态属性(如cZxidctime等);
  • 通过-w成功为/test节点注册了 Watcher 监听(监听节点数据变更)。
  • 2. 后续验证步骤

  • 打开另一个 ZooKeeper 客户端,执行set /test "new_data"修改/test的数据;
  • 回到当前客户端,会收到NodeDataChanged事件通知(显示类似WatchedEvent state:SyncConnected type:NodeDataChanged path:/test的内容)
  • 该 Watcher 是 “单次生效” 的,收到通知后若需继续监听,需再次执行get -s -w /test重新注册。

    ZooKeeper 的 Watcher(监听通知)机制具有以下核心特点:

    1. 单次触发

    Watcher 是 “一次性” 的,客户端收到事件通知后,监听关系自动失效;若需持续监听,必须重新注册。

    2. 异步推送

    通知由 ZooKeeper 服务端主动推送给客户端,无需客户端轮询,降低资源消耗。

    3. 轻量通知

    通知仅包含事件类型(如NodeDataChanged)和节点路径,不携带具体变更数据;客户端需主动查询最新数据。

    4. 会话绑定

    Watcher 注册与客户端会话绑定:若会话断开(如客户端下线),未触发的 Watcher 会失效。

    5. 事件驱动

    仅当节点发生指定变更(数据修改、子节点增删)时才触发,无变更则无通知,保证高效性。

    ZooKeeper 的 Watcher 机制

    分布式协同服务中是核心支撑能力,典型的使用案例包括 分布式配置中心集群节点上下线感知分布式锁 这三类,以下是具体的实现逻辑和实操说明:

    一、 案例 1:分布式配置中心(配置动态推送)

    核心场景;分布式系统中,多台服务实例需要共享一份配置(如数据库连接参数、限流阈值),当配置修改时,所有实例需自动感知并更新,无需重启服务。

    基于 Watcher 的实现流程

    配置存储在 ZooKeeper 上创建一个持久节点存储配置,例如:

    create /config/serviceA "db.url=jdbc:mysql://localhost:3306/test;timeout=5000"

    客户端注册监听每个服务实例启动时,读取get-w /config/serviceA 的配置,同时注册 Watcher 监听节点数据变更

    配置更新触发通知运维人员修改配置节点数据

    set /config/serviceA "db.url=jdbc:mysql://new-host:3306/test;timeout=10000"

    ZooKeeper 会向所有注册了 Watcher 的服务实例推送 NodeDataChanged 事件。

    客户端响应服务实例收到通知后,主动重新读取 /config/serviceA 的最新配置,完成动态更新。

    核心优势

  • 无需轮询,配置变更实时推送;
    • 天然支持多实例协同,一致性高。

    二、 案例 2:集群节点上下线感知(服务发现)

    核心场景:分布式集群(如微服务集群、大数据计算集群)需要实时感知节点的上线、下线状态,以便进行负载均衡或任务重分配。

    基于 Watcher 的实现流程

    1创建集群根节点

    节点上线:创建临时节点 + 监听子节点

    每个服务节点启动时,在 /cluster/serviceA 下创建临时子节点,节点名携带自身信息(如 IP + 端口):

    create -e /cluster/serviceA/node-192.168.1.100:8080 "weight=10"

    集群的管理节点(或其他服务节点)监听根节点的子节点变化

  • 节点下线:临时节点自动删除 + 触发通知当某个服务节点宕机或主动下线时,客户端会话断开,对应的临时节点会被 ZooKeeper 自动删除。ZooKeeper 向管理节点推送 NodeChildrenChanged 事件。
  • 管理节点响应管理节点收到通知后,重新执行 ls /cluster/serviceA 获取最新的节点列表,更新负载均衡策略。
  • 临时节点自动清理,无需手动维护下线节点;

    子节点监听可实时感知集群拓扑变化。

    三、 案例 3:分布式锁(公平锁实现)

    创建锁根节点先创建一个持久根节点作为锁的命名空间:

    create /lock/order-lock ""

    竞争锁:创建临时顺序节点

    create -e -s /lock/order-lock/lock- "" # -s 表示顺序节点,会生成如 lock-0000000001 的节点名

    判断是否获得锁 + 注册前驱节点监听节点创建成功后,获取 /lock/order-lock 下的所有子节点并排序;

  • 如果自己创建的节点是序号最小的,说明获得锁,可执行资源操作;
  • 如果不是最小的,找到自己的前驱节点,并注册 Watcher 监听前驱节点的删除事件:
  • 锁场景作用:所有竞争锁的客户端,创建的节点都会被分配一个从小到大的序号,天然形成「排队顺序」,先创建的序号小,后创建的序号大,完美实现公平锁(谁先来谁先拿锁)
  • 在 ZooKeeper 分布式锁场景中,“序号排队” 之后的公平锁实现逻辑,是通过「节点排序 + 前驱节点监听」的组合完成的,这是一个 **“排队 - 等待 - 唤醒” 的闭环流程 **,下面分步骤拆解清楚:

    一、核心逻辑:“序号排队” 只是基础,关键是「谁排第一谁拿锁」

    当所有客户端都创建了带序号的节点后,ZK 会保证序号是全局唯一且严格递增的(比如lock-0000000000lock-0000000001lock-0000000002),此时的 “公平” 体现在:

    序号最小的节点,就是当前排队的第一个,拥有「优先拿锁权」

    二、具体实现步骤(序号排队后的完整流程)

    假设现在有 3 个客户端竞争锁,已创建的节点列表是:

    [lock-0000000000(客户端A)、lock-0000000001(客户端B)、lock-0000000002(客户端C)]

    步骤 1:判断自己的节点是否是「序号最小」

    每个客户端都会执行以下操作:

    • 执行ls /lock/order-lock获取所有节点,按序号从小到大排序
    • 对比 “自己创建的节点” 和排序后的列表:客户端 A:自己的节点是lock-0000000000(序号最小)→ 直接获得锁,开始执行业务逻辑;客户端 B:自己的节点是lock-0000000001(不是最小)→ 进入等待;客户端 C:自己的节点是lock-0000000002(不是最小)→ 进入等待。

    步骤 2:未拿锁的客户端,“绑定” 自己的「前驱节点」

    “前驱节点” 是指排序后紧邻自己的前一个节点(序号比自己小 1):

    • 客户端 B 的前驱节点是lock-0000000000(客户端 A 的节点);
    • 客户端 C 的前驱节点是lock-0000000001(客户端 B 的节点)。

    每个未拿锁的客户端,都会给自己的前驱节点注册一个「删除监听」(用你之前写的命令):

    bash

    运行

    # 客户端B执行
    get -w /lock/order-lock/lock-0000000000
    
    # 客户端C执行
    get -w /lock/order-lock/lock-0000000001
    
    

    此时客户端 B、C 进入阻塞等待状态,不再做任何操作,只等 “前驱节点被删除” 的信号。

    步骤 3:锁释放→监听触发→重新排队拿锁

    持有锁的客户端 A执行完业务逻辑后,会主动删除自己的节点(释放锁):

    bash

    运行

    delete /lock/order-lock/lock-0000000000
    

    此时:

    1. 客户端 B 注册的「前驱节点监听」会被触发(日志显示NodeDeleted)→ 客户端 B 被 “唤醒”;
    2. 客户端 B 立刻重新执行ls /lock/order-lock,获取最新节点列表(此时列表是[lock-0000000001、lock-0000000002]);
    3. 客户端 B 发现自己的节点lock-0000000001现在是「序号最小」→ 获得锁,开始执行业务逻辑;
    4. 客户端 C 的前驱节点变成lock-0000000001(客户端 B 的节点),继续等待其释放。

    步骤 4:循环执行,实现 “公平排队”

    这个流程会循环下去

    • 客户端 B 释放锁→客户端 C 被唤醒→客户端 C 拿锁;
    • 新的客户端加入竞争,会创建新的序号节点,自动插入到排队列表的末尾;
    • 整个过程严格按照 “节点序号从小到大” 的顺序拿锁,完全符合 “谁先来谁先拿” 的公平性

    三、为什么这是 “完美公平锁”?

    1. 序号的全局唯一性:ZK 的-s参数保证所有节点的序号是全局递增的,先创建的序号一定更小;
    2. 监听的精准性:每个客户端只监听自己的前驱节点,不会 “插队” 或 “抢锁”;
    3. 无饥饿问题:无论等待多久,只要前驱节点释放锁,当前客户端一定会被唤醒并获得拿锁的机会。

    总结:公平锁的实现本质

    “序号排队” 是基础,“前驱节点监听 + 唤醒后重新判断” 是核心—— 通过这两个步骤,把 “无序的竞争” 转化为 “有序的等待”,最终实现严格的公平锁。

    zookeeper 的 ACL(Access Control List,访问控制表)权限

    在生产环境是特别重要的,ACL 权限可以针对节点设置相关读写等权限,保障数据安全性。

    ZooKeeper 的 ACL 权限用于控制客户端对 ZNode 节点的操作权限,核心规则如下:

    1. 权限类型(共 5 种)

    • CREATE(C):允许创建子节点
    • READ(R):允许读取节点数据及子节点列表
    • WRITE(W):允许修改节点数据
    • DELETE(D):允许删除子节点
    • ADMIN(A):允许设置节点的 ACL 权限

    2. 权限标识方式

    ZooKeeper 的 ACL 由[权限模式:授权对象:权限]组成,常见权限模式包括:

    • IP 模式:基于客户端 IP 授权(如ip:192.168.1.1:rw
    • Digest 模式:基于用户名 / 密码的哈希授权(如digest:user:passwdHash:cdrwa
    • World 模式:所有客户端默认权限(仅world:anyone:r
    • Super 模式:超级用户权限(需配置超级用户后使用)

    3.常见操作示例

    以下是 ZooKeeper ACL 权限的常见操作示例,覆盖不同权限模式和场景:

    一、World 模式(默认权限)

    World 模式是最宽松的权限,对所有客户端开放

    运行

    # 创建节点时设置默认World权限(仅读)
    create /test "data" world:anyone:r
    
    # 查看ACL(默认就是world:anyone:r)
    getAcl /test
    # 输出:'world,'anyone
    # : r
    

    二、IP 模式(基于客户端 IP 授权)

    限制特定 IP 的客户端才能操作节点:这里有一些服务端与客户端的权限问题字自己ai一些就可以解决这是我的·

    bash

    运行

    # 创建节点并授予rw+a权限
    create /node "ip_data" ip:192.168.1.100:rwa
    # 修改ACL
    setAcl /node ip:192.168.1.100:rwa,ip:10.0.0.5:r
    

    三.auth授权模式

    ZooKeeper 的auth授权模式是基于 “已登录账号” 的权限控制方式,属于常用的 ACL 权限模式之一,以下是详细说明:

    auth模式的权限对象是当前客户端已通过addauth命令登录的账号,权限规则会自动关联到已登录的账号,无需在权限中显式指定账号信息。

    步骤 1:登录账号(在 ZK 客户端内执行)

    # 格式:addauth 认证方案 账号:密码 addauth digest user1:123456

    步骤 2:创建节点并配置auth权限

    # 创建节点时,权限写为auth:权限值 create /auth_node "data" auth:user1:rw

    步骤 3:验证权限

    • 登录user1的客户端可正常操作:get /auth_node/set /auth_node "new_data"
    • 未登录账号的客户端执行上述操作会提示 “权限不足”

    Zookeeper集群

    等待写

    全部评论
    当笔记更新每天写点
    点赞 回复 分享
    发布于 昨天 16:04 河北

    相关推荐

    不愿透露姓名的神秘牛友
    2025-12-16 14:41
    点赞 评论 收藏
    分享
    评论
    点赞
    收藏
    分享

    创作者周榜

    更多
    牛客网
    牛客网在线编程
    牛客网题解
    牛客企业服务