Zookeeper数据结构

本文为个人学习笔记整理,仅供交流参考,非专业教学资料,内容请自行甄别。

文章目录


一、Zookeeper数据模型

Zookeeper 的数据模型采用了一种类似文件系统的树形结构。在这个树形结构中,每个节点被称为 Znode,它是 Zookeeper 数据模型的基本单元,就如同文件系统中的文件或目录。每个 Znode 都有一个唯一的路径,用于标识其在 Zookeeper 树中的位置,例如 "/config/database" 就表示了一个位于 "/config" 节点下的 "database" 子节点 ,通过这种路径标识,客户端可以方便地对 Znode 进行创建、读取、更新和删除等操作。

Znode 不仅可以存储数据,还可以拥有子节点,从而形成复杂的层级结构。在一个分布式系统中,我们可以在 "/services" 节点下创建多个子节点,如 "/services/service1""/services/service2" 等,分别用于存储不同服务的相关信息;而在每个服务节点下,还可以进一步创建子节点,如 "/services/service1/instance1""/services/service1/instance2",用于记录服务的不同实例的状态、地址等数据 。不过,Znode 存储的数据量是有限的,默认情况下,每个 Znode 最多能存储 1MB 的数据,这就决定了 Znode 主要用于存储一些关键的元数据、配置信息或状态信息等,而不适合存储大量的业务数据。

1.1、节点类型

节点类型一般可以分为以下五种:

  • 持久节点:创建之后一直存在,直到被显式删除。生命周期与客户端会话无关。可以创建一个持久节点 "/config",并在其下创建子节点来存储各种配置信息,如数据库连接字符串、系统参数等。这些配置信息通常是长期稳定的,需要在系统运行期间一直存在,持久节点正好满足了这一需求。
  • 临时节点:临时节点的生命周期与客户端会话紧密绑定,当客户端与 Zookeeper 服务器建立的会话断开,超时,或者出现异常,该客户端创建的临时节点会被自动删除。这一特性使得临时节点非常适合用于实现一些临时状态的记录和监控,以及分布式锁等场景。在分布式锁的实现中,多个客户端竞争在 "/lock" 节点下创建临时节点,只有成功创建的客户端才能获得锁,当客户端完成操作并断开会话时,其创建的临时节点会自动删除,从而释放锁,让其他客户端有机会获取。
  • 有序节点:顺序节点结合了持久节点和顺序节点的特性。有序节点可以是临时的也可以是持久的,在创建时,Zookeeper 会自动为其附加一个唯一的序列号,这个序列号是单调递增的,由父节点维护。
  • 容器节点: 当容器节点的最后一个子节点被删除后,容器节点也会被删除。
  • TTL节点:在TTL内没有被修改,并且没有子节点时,会被删除。

1.1.1、创建持久节点

创建持久节点:

create /节点名

1.1.2、创建临时节点

创建临时节点:

create -e /节点名

在重启后会丢失(注意,这里的重启是重启服务端)

1.1.3、创建有序节点

创建有序节点,临时和非临时:

create -e -s /节点名

create -s /节点名

1.1.4、创建容器节点

创建容器节点:

create -c /节点名

当其所有的子节点被删除时,该节点也会被删除(非实时,Zookeeper底层通过定时任务扫描)

1.1.5、创建TTL节点

默认此功能不开启,需要修改配置文件,extendedTypesEnabled=true

create -t 时间(单位毫秒) /节点名

当该节点在ttl中没有没有被修改并且没有子节点,该节点也会被删除(非实时,Zookeeper底层通过定时任务扫描)

2、节点状态信息

可以使用stat [-w] path命令去查看某个节点的具体状态信息:

其中的关键信息:

  • cZxid:该节点的事务ID,每次写操作都会生成一个递增的 Zxid,因此可以通过 Zxid 判断操作的先后顺序。
  • ctime:代表节点被创建的时间。
  • mZxid:代表节点最后一次被修改数据时的事务 ID。Zxid对于Zookeeper来说是全局唯一的,不是绑定在单个节点上的。
  • mtime:代表节点最后一次被修改数据的时间。
  • pZxid:代表节点最后一次添加 / 删除子节点时的事务 ID,但是修改子节点的内容,不会触发pZxid的更新。
  • cversion:代表该节点子节点的版本号,每次添加或者删除子节点时,该值会递增。
  • dataVersion:代表该节点数据内容的版本号,每次使用set操作新增数据,该值都会递增,注意,这和新增数据的内容没有关系,即使新增的数据内容相同,该值也会递增。
  • aclVersion:代表节点访问控制列表(ACL)的版本号,每次使用setacl修改节点的权限,该值都会递增。
  • ephemeralOwner:用于标识节点是否为临时节点,如果是临时节点,该值为创建它的会话的 ID,如果是持久节点,该值为 0x0。
  • dataLength:代表节点存储的数据内容的长度(字节数)
  • numChildren:代表节点的子节点数量,不会去递归统计,而是统计当前节点直属的子节点,当前节点子节点的子节点,不会被统计到。

2.1、节点类型应用场景

2.1.1、永久节点

永久节点可以用于存放一些配置信息,通过 Watcher 机制,客户端可以监听永久节点的变化(如配置更新),实现配置的动态推送和实时同步,无需重启服务即可生效。实现分布式锁时,通常会创建一个永久节点作为锁的 "根目录"(如 /locks),然后在其下创建临时顺序节点作为具体的锁实例。根节点需要长期存在,以保证锁机制的稳定性(否则每次客户端会话断开后根节点消失,会导致锁机制失效)。

2.1.2、临时节点

临时节点可以实现锁的操作,例如A客户端通过创建临时节点的命令加锁

B客户端再次加锁是失败的,因为节点已经存在:

只有A客户端在执行完业务代码,并且删除该节点后,B客户端才可以再次加锁(通过监听机制),使用临时节点的目的是,防止A客户端获取到锁,然后断开连接,造成死锁的问题。

2.1.3、顺序节点

仅用临时节点(非顺序)也能实现分布式锁的互斥性(同一时刻只有一个客户端能创建节点),但无法解决公平性和效率问题,而临时顺序节点的 "顺序性" 正是为了弥补这些缺陷。具体来说,两者的核心差异体现在锁的竞争方式和等待机制上:

  • 如果要实现公平锁,临时节点没有顺序,当持有锁的客户端释放锁(删除 /lock)后,所有等待的客户端会同时收到事件通知,并尝试重新创建 /lock 节点。此时,ZooKeeper 会随机(或按网络延迟等非可控因素)选择一个客户端成功创建节点,导致后发起请求的客户端可能 "插队" 抢到锁,破坏了 "先到先得" 的公平性。
  • 当 /lock 节点被删除时,所有监听该节点的客户端会同时被唤醒,并尝试创建节点。但最终只有一个客户端能成功,其余客户端都会失败,需要重新进入等待。这样一次性唤醒所有等待者的现象,称为惊群效应,可能会造成大量客户端同时发送创建请求,造成瞬时流量峰值,失败的客户端需要重新监听、等待,增加无效的 CPU / 网络开销。

使用临时顺序节点,就可以解决上述的问题,所有客户端在竞争锁时,会在根节点(如 /locks)下创建临时顺序节点:

客户端A

客户端B

  • 每个客户端创建节点后,会查询根节点下的所有子节点,并按序号排序;
  • 若自己的节点是序号最小的(第一个),则直接获得锁;
  • 若不是,则只需要监听前一个序号的节点(如序号为 3 的节点监听序号为 2 的节点)。

由于每个客户端只监听 "前一个节点",当持有锁的客户端释放锁(删除自己的节点,如 lock-000000001)时,只有紧随其后的客户端(监听 lock-000000001 的 lock-000000002)会被唤醒,其他客户端仍处于等待状态。

2.1.4、容器节点和TTL 节点

容器节点的核心价值是 "自动清理空容器" ,适合作为 "子节点集合的临时载体",避免子节点全部消失后残留空节点,减少手动维护成本。微服务架构中,可按服务类型创建容器节点(如 /services/user-service),每个子节点代表一个在线的服务实例(如 /services/user-service/instance-1)当该服务的所有实例下线(子节点删除),容器节点 /services/user-service 会被自动清理,避免注册中心中残留 "无实例的服务空节点"

TTL 节点的核心价值是 "时间驱动的自动过期清理",适合存储 "需要定期刷新否则自动失效" 的持久数据,无需手动设置定时任务删除。在分布式系统中可以作为存储节点的 "临时健康状态"(如 /health/node-1),设置 TTL 为 30 秒。节点需每 30 秒内发送一次心跳(更新节点数据),若节点故障无法心跳,TTL 到期后状态节点自动删除,监控系统可感知节点异常。

相关推荐
青云交2 小时前
Java 大视界 --Java 大数据机器学习模型在金融风险压力测试中的应用与验证
java·随机森林·机器学习·lstm·压力测试·联邦学习·金融风险
程序编程- Java2 小时前
和平精英java 游戏程序
java·游戏程序·安全架构·玩游戏
happy_king_zi2 小时前
RabbitMQ直接查看队列中消息的内容
分布式·rabbitmq
oioihoii2 小时前
C++中的多态:动态多态与静态多态详解
java·开发语言·c++
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于Java的医务室病历管理小程序为例,包含答辩的问题和答案
java·开发语言·小程序
沐浴露z2 小时前
详解 零拷贝(Zero Copy):mmap、sendfile、DMA gather、splice
java·网络·操作系统
kyle~2 小时前
C++---关键字constexpr
java·开发语言·c++
dllxhcjla2 小时前
css第二天
java·前端·css
春生野草2 小时前
SpringBoot配置文件
java·数据库·spring boot