zookeeper 节点类型从持久化层面只有 2 种,分为持久节点(persistence znode)和临时节点(ephemeral znode);如果实现层面又分成其他 2 种,顺序节点(sequential znode)和非顺序节点;若再把失效机制加一起后,总共可分为如下 7 种:
- 持久节点(persistence znode);
- 临时节点(ephemeral znode);
- 持久顺序节点(persistent_sequential znode);
- 临时顺序节点(ephemeral_sequential znode);
- 容器节点(container znode);
- 持久 TTL 节点(persistent_ttl znode);
- 持久顺序 TTL 节点(persistent_sequential_ttl znode)。
持久节点
顾名思义,持久节点(persistence znode)不管是 client 是否连接,该节点都存在有效;默认情况下,zookeeper 所有的 znode 都是持久的。
使用场景主要如下:
- 一般带有子目录的都是持久的(想想若父目录随时可删除,子目录岂不是很危险);
- 像 dubbo、spring cloud 使用 zookeeper 作为注册中心时,项目目录是持久的(其实是上面的一个应用场景);
- 把 zookeeper 当作配置中心使用时,具体路径配置节点也是持久的(这没什么可解释的)。
临时节点
临时节点(ephemeral znode)存在即表示其一直处于活动状态(active);临时节点的生命周期和客户端会话绑定在一起,客户端会话失效,则这个节点就会被自动清除。
zookeepr 如何认定会话失效,从而删除临时节点呢?这里整理了几个重要知识点:
- Zookeeper 客户端和服务端维持一个长连接,一般初始化连接的时候需要设置心跳间隔时间,如 5s,这其实也是 session 有效的检查时间间隔;
- Zookeeper 服务端给客户端的一个长连接分配拥有全局唯一的 session id,zk 服务端就是依据该 session 是否生效来判断是否删除临时节点;
- zk 删除临时节点有2种原因,一是客户端主动关闭连接被认为是一次 session 失效;另一种是网络超时导致 client 没有请求到 server;在服务端看来,无法区分 session 失效是何种情况,一旦发生一次 session 失效,一定时间后就会将 session 持有的所有 watcher 以及瞬时节点删除。
使用场景如下:
- 在 zookeeper 本身的 leader 选举中,临时节点扮演着重要的角色;
- 像 dubbo、spring cloud 使用 zookeeper 作为注册中心时,实例 ip 信息的注册节点是临时的,应用服务关闭或重启时会瞬间删除掉。
持久顺序节点
顺序节点(sequential znode)表示节点和节点之间是有顺序关系的,它也分为持久的和临时的。
当一个新的 znode 作为顺序 znode 创建时,ZooKeeper 通过将 10 位序列号和原始名称拼接在一起来设置 znode 的路径。例如,如果将路径为 /myapp
的 znode 创建为顺序节点,ZooKeeper 会将路径更改为 /myapp0000000001
并将下一个序列号设置为 0000000002
。如果同时创建两个顺序 znode,则 ZooKeeper 永远不会使用相同的编号每个 znode。
使用场景:
- 分布式公平锁;
- 分布式队列;
- 分布式同步。
临时顺序节点
和持久顺序节点一样,只是删除遵循临时节点的机制。
容器节点
容器节点(container znode)是 zookeepr 3.5.3 版本开始增加的。
只要在调用 create 方法时指定 CreateMode
为 CONTAINER
即可创建容器的节点类型,容器节点的表现形式和持久节点是一样的,但是区别是 ZK 服务端启动后,会有一个单独的线程去扫描,所有的容器节点,当发现容器节点的子节点数量为 0 时,会自动删除该节点,除此之外和持久节点没有区别。
由于容器节点的该特性,当你在容器节点下创建一个孩子节点时,应该会遇到 KeeperException.NoNodeException 报错,该异常,则需要重新创建容器节点。
使用场景:
- 在 leader 选举场景;
- 锁场景中应用。
持久 TTL 节点
ttl 节点(ttl znode)也是 zookeepr 3.5.3 版本开始增加的。
ttl 节点是针对持久节点和持久顺序节点来说的,TTL 是 time to live 的缩写,指带有存活时间,简单来说就是当该节点下面没有子节点的话,超过了 TTL 指定时间后就会被自动删除,特性跟上面的容器节点很像,只是容器节点没有超时时间而已,但是 TTL 启用是需要额外的配置,zookeeper.extendedTypesEnabled
需要配置成 true
,否则的话创建 TTL 时会收到 KeeperException.UnimplementedException
的报错。
持久顺序 TTL 节点
和持久 TTL 节点的机制一样,只是多了顺序性的机制。