很多人在回答 ZooKeeper 节点类型时,习惯性地说只有 4 种:持久、持久顺序、临时、临时顺序。这个说法并不完整。以 ZooKeeper 3.6.2 为例,服务端实际支持 7 种节点类型。
这 7 种分别是:持久节点、持久顺序节点、临时节点、临时顺序节点、容器节点、持久 TTL 节点、持久顺序 TTL 节点。
下面按照特性和使用场景,系统梳理一下这些节点类型的区别,以及它们在服务端侧的大致实现方式。
ZooKeeper 的 7 种节点类型
1. 持久节点
持久节点是最常见、也是默认的节点类型。只要客户端不主动删除,它就会一直存在,不会因为会话结束而消失。
这类节点适合保存需要长期存在的配置信息、注册信息或业务状态。
2. 临时节点
临时节点和持久节点的主要区别在于生命周期。它会随着客户端会话结束而自动删除。
因此,临时节点常用于一些与连接状态强相关的场景,例如:
- 服务实例存活探测
- 健康检查
- 分布式锁占用标记
3. 持久顺序节点
顺序节点的特点是:创建时,ZooKeeper 会在节点路径后自动追加一个递增的数字后缀。这样可以保证同一父节点下生成的路径具有唯一性。
持久顺序节点既保留了持久节点的特性,又增加了顺序编号,常见用途包括:
- 分布式队列
- 需要排序的任务列表
- 有序事件记录
4. 临时顺序节点
临时顺序节点同时具备两个特点:会话结束后自动删除,以及自动追加顺序编号。
这类节点非常适合实现:
- 分布式公平锁
- 选主流程中的排队机制
- 临时有序注册
5. 容器节点
容器节点是 ZooKeeper 3.5 之后新增的类型。创建时只需在 create 方法中指定 CreateMode 为 CONTAINER。
从使用表现来看,容器节点和持久节点很像,但它多了一个自动清理能力:服务端启动后,会有专门的后台线程定期扫描容器节点。当发现某个容器节点已经没有子节点时,就会自动删除该节点。
除了这个自动清理特性外,它与持久节点没有本质差别。
这种节点适合用于一些“父节点只是为了挂载子节点而存在”的场景,例如:
- Leader 选举
- 锁目录管理
- 临时协调目录
6. 持久 TTL 节点
TTL 是 time to live 的缩写,表示存活时间。持久 TTL 节点本质上还是持久节点,但它带有超时控制能力。
当节点没有子节点,并且超过设定的 TTL 时间后,服务端会自动删除它。
它和容器节点很相似,区别在于:
- 容器节点的删除条件主要是“没有子节点”
- TTL 节点除了要求没有子节点外,还会受到 TTL 时间限制
需要注意的是,TTL 类型默认并不能直接使用,必须开启额外配置:
zookeeper.extendedTypesEnabled=true
如果没有开启该配置,创建 TTL 节点时通常会收到 Unimplemented 错误。
7. 持久顺序 TTL 节点
这种节点是在“持久顺序节点”的基础上,再叠加 TTL 能力。也就是说,它既会自动追加顺序编号,又支持在满足条件时按 TTL 自动清理。
适合需要“有序生成 + 自动过期回收”的场景。
顺序节点的实现原理
顺序节点的原理其实并不复杂。客户端在创建顺序节点时,服务端识别到该节点属于 sequential 类型,就会在原始路径后拼接一个固定宽度的数字后缀。
常见逻辑可以概括为:
如果节点是顺序节点,那么路径会变成:原始路径 + 格式化后的编号。
这个编号通常与父节点的版本信息相关,可以理解为当前父节点下子节点创建次数的递增序号。这样一来,生成出来的完整路径天然具备唯一性和有序性。
容器节点和 TTL 节点的清理机制
容器节点和 TTL 节点虽然使用方式不同,但在服务端侧的处理思路比较接近。
ZooKeeper 启动后,会额外启用一个后台定时任务线程,周期性扫描这两类节点,并根据节点状态决定是否删除。相关逻辑位于 ContainerManager 中,定时任务通过 TimerTask 执行。
扫描过程中,服务端会结合以下因素判断节点是否应被清理:
- 节点是否还有子节点
- TTL 是否已到期
- 节点最后一次更新时间
- 相关清理参数配置
相关配置项
与容器节点和 TTL 节点清理有关的常见配置包括:
- znode.container.checkIntervalMs:默认 60000 毫秒,表示后台定时任务的检查间隔。
- znode.container.maxPerMinute:默认 10000,和上面的配置共同决定扫描节奏。按默认值计算,两个节点之间的最小检查间隔大约为 6 毫秒。
- znode.container.maxNeverUsedIntervalMs:默认 0。如果该值不为 0,那么当容器节点或 TTL 节点距离最后更新时间超过这个阈值时,也可能被删除。
如何理解这 7 种节点
如果把 ZooKeeper 节点类型拆成几个关键字来理解,会更容易记忆:
- 持久:客户端不删除,就会一直存在。
- 临时:会话断开后自动删除。
- 顺序:服务端自动追加数字后缀。
- 容器:服务端会定期扫描,没有子节点时可自动删除。
- TTL:需要额外开启配置,在满足条件且超过生存时间后自动删除。
其中,TTL 节点还有一个值得注意的行为:当节点下再次创建子节点时,它的超时计时会被重置,因此它并不是简单地“到点必删”,而是与节点活跃度有关。
总结
ZooKeeper 的节点类型并不只是常见的 4 种。从较新的版本能力来看,完整范围应当包括 7 种:
- 持久节点
- 持久顺序节点
- 临时节点
- 临时顺序节点
- 容器节点
- 持久 TTL 节点
- 持久顺序 TTL 节点
如果只是应对基础使用,前 4 种已经覆盖了大多数场景;但如果涉及自动清理、目录回收、过期控制等需求,那么容器节点和 TTL 节点就非常值得了解。
因此,再遇到“ZooKeeper 有几种节点类型”这个问题时,更准确的回答应该结合具体版本来说:至少在 3.6.2 中,服务端支持 7 种节点类型,而不是简单的 4 种。
