【分布式ID】【Snowflake变种】用 ZooKeeper 维护 Worker ID
程序员文章站
2022-05-30 10:49:30
...
Twitter 推出的 Snowflake 是一个非常实用的分布式ID生成方案。它的默认设置中,各部分信息所占比特位比较有代表性,通常无需二次定制。但是对于 datacenter id 和 worker id 的维护需要各项目自行设计方案。
通常,datacenter id 是固定的,一旦为各数据中心分配好ID,几乎不会变更。但各数据中心内部的 worker id 可能会因ID生成服务实例的动态创建销毁,而需要有一套动态的协调机制,以防同一数据中心内多个实例共用同一个 worker id。
本例就是利用 ZooKeeper 来协调分配 worker id。
源码:snowflake-worker-id-with-zk
关键类:IdGenCoordinator
此类用于协调分配 worker id。
基本原理
基本原理是 以创建 ZooKeeper 节点的方式来表示哪些 worker id 已被占用。
节点树结构示例:
- /example/id-gen/worker-ids 的子节点表示当前已被占用的 worker id。
其中各节点内容就是使用该 worker id 的id生成器实例的ip地址。 - /example/id-gen/gens 的子节点表示当前活跃的id生成生成器实例。
其中各节点内容就是相应生成器实例所使用的 worker id。
初始化步骤
- 1. 创建必要的 ZooKeeper 父节点。
“/example/id-gen/worker-ids” 和 “/example/id-gen/gens” 是必要的父节点。注意,需要处理 NodeExistsException,因为各 id 生成器实例启动时都会执行该操作。 - 2. 注册 ZooKeeper 连接状态变更事件处理器。
防止多个 id 生成器服务实例使用同一个 worker id。 - 3. 获取 worker id 并启动 id生成器服务
ZooKeeper 连接状态处理
- 当生成器与 ZooKeeper 断开连接时,需停止服务,以防多个生成器实例使用同一个 worker id;
- 当生成器与 ZooKeeper 重新连接时,需重新获取 worker id,因为原 worker id 可能已被其它实例占用。
获取 worker id 的关键逻辑
- 1. 尝试获取对应的 ZK 节点内容。
如 “/example/id-gen/gens/10.1.100.101”。
若成功获取,说明该服务实例已注册,节点内容就是已分配给它的 worker id;否则进行下一步:注册。 - 2. 从最小 worker id 开始,至最大 worker id,尝试创建相应的 ZK 节点。
若创建成功,则表示成功获得相应的 worker id。否则认定为失败。
需要创建两个节点,且必须在同一个ZooKeeper事务中完成。如,在一个事务中创建:
/example/id-gen/worker-ids/0 (节点内容为 10.1.100.101)
/example/id-gen/gens/10.1.100.101 (节点内容为 0)