这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天。
本文以 CC-BY-SA 4.0 发布。
Zookeeper
Zookeeper 直译为动物园管理员。 根据文档, 它可以用来为分布式系统提供配置信息、命名、分布式同步和分组服务。 这些服务其实也已经成为了现今的分布式系统里不可或缺的一部分。
当然,用其它的服务,例如 Redis 或是 etcd 也可以通过额外写相应的代码来实现这些功能, 但是,实现这些功能、对其进行 debug(特别是并发等的临界状态下的 bug)并不是一件容易的事情。 而最终这部分代码维护、管理起来也困难, 不同服务(例如不同语言写成的)之间要保持一致并进行共同部署也更加困难。
比如我之前手写了一个分布式节点 ID 分发的方法 (使用 etcd 分配全局唯一节点 ID | 青训营笔记), 但是 Zookeeper 已经提供了与之类似的持久/临时顺序节点的功能,不必重造轮子。
理解
和 etcd 类似,Zookeeper 其实也可以看作是一个键值数据库, 不同的是 Zookeeper 明确有一个类似文件系统的目录的层次模型。
graph TD
root["/"] --> etc["/etc"]
etc --> service1["/etc/service1"]
etc --> service2["/etc/service2"]
service1 --> conf1["/etc/service1/conf1"]
service1 --> conf2["/etc/service1/conf2"]
Zookeeper 的一个树状节点可以分为多个种类:
PERSISTENT: 持久性EPHEMERAL: 临时,与 etcd 的附上了 lease 的键值对类似,需要客户端心跳进行 keepalivePERSISTENT_SEQUENTIAL:PERSISTENT+ 顺序性EPHEMERAL_SEQUENTIAL:EPHEMERAL+ 顺序性
分配全局唯一节点 ID 的方案
思路其实与 etcd 类似,但是利用 Zookeeper 的一些功能我们可以更方便地实现以下功能:
- 每个节点获得一个独立 ID
- ID 在节点下线之后可以自动回收
思路是:
- 创建一个持久性节点
/ID_GEN,用来不断生成顺序的 ID; - 创建一个持久性节点
/NODE_ID,用来记录已经上线的节点; - 每有一个节点上线,则先在
/ID_GEN下创建一个临时顺序节点/ID_GEN/idXXXXXXXXXX, 其中XXXXXXXXXX就是 Zookeeper 自动分配的序列号; - 因为十位数可能超过了理想 ID 的范围,所以我们需要取模成
YYYY之后尝试创建一个临时节点/NODE_ID/idYYYY, 用来记录我们这一 ID 已被使用; - 如果临时节点创建失败,则说明已经有其它节点使用了相同的 ID,我们需要从
3.开始重试。
整体流程和 etcd 下一致。不同的是因为 Zookeeper 提供了一个获取顺序数字的方法, 让我们可能更容易地进行整体规划,而 etcd 则是需要从 CAS 的原子操作写起, 需要自行设计获取顺序数字的方法。