机器 ID 分配

合理分配机器 ID 是雪花算法正常工作的关键。

上一节处理的是时间,这一节处理的是身份。前面的章节反复强调过同一个约束:只要两个同时存活的节点持有同一个机器 ID,它们在同一毫秒生成的 ID 就会完全相同。这个故障不报错、不告警,通常要等数据重复了才被发现,而排查和修复数据的代价极高。

分配方式可以归成三类。手动分配用配置文件或数据库登记已经分配出去的 ID,机器数量少的时候最省事,但扩容和换机器都要人工介入。自动分配把注册中心交给 ZooKeeper 或 etcd,实例上线领号、下线注销,天然避免冲突,代价是引入了一个必须高可用的协调服务。基于 IP 分配把地址的最后几位映射成机器 ID,不需要任何外部组件,可一旦 IP 被复用或变更就会静默冲突。

这套机制要满足的关键约束是:同一时间窗口内不能有两个活跃实例持有同一个机器 ID。

读完这一章,你应该能结合自己的部署形态(物理机、云主机、容器编排)选出一套分配方案,并说明它如何与租约、回收和监控配合,以及协调服务不可用时应该怎么做。

分配策略

1. 手动分配

管理: 使用配置文件或数据库记录已分配的 ID。

2. 自动分配

使用 ZooKeeper: 用 ZooKeeper 或 etcd 作为机器 ID 的注册中心,实例启动时在固定路径下创建一个临时顺序节点,节点序号就是机器 ID;实例下线时临时节点被自动删除,这个 ID 可以被下一个实例安全复用。

注册中心路径:/snowflake/machine-id/
实例启动 → 创建临时顺序节点 → 拿到顺序号 N(0~31)→ N 即机器 ID
实例存活 → 定期续约(etcd lease / ZooKeeper session)
实例下线 → 临时节点自动消失 → 序号释放给下一个实例

需要处理两个边界。其一,注册中心不可用时不能随便取号——那样等于放弃了唯一性保证,正确的做法是让实例启动失败,或者让发号接口明确返回不可用。其二,容器环境下 Pod 重建会频繁更换 IP,机器 ID 应当绑定到实例的生命周期而不是网络地址,否则一个还没真正下线的旧实例会和新实例抢到同一个号。


3. 基于 IP

把 IP 地址的最后几位映射成机器 ID,不需要任何外部组件,配置最轻。常见做法是取 IP 最后一段的低 5 位:

IP 192.168.1.37 → 取最后一段 37 → 37 & 0x1F = 5 → 机器 ID = 5

但这种方案的失败模式是静默的:虚拟机迁移、容器重建、云主机更换 IP,都可能在不告警的情况下让两个节点拿到同一个号;节点数超过 32 台之后,低 5 位还会直接绕回。

结论是:基于 IP 的方案适合节点固定、IP 静态分配、规模很小的内网环境;一旦进入生产环境、节点会弹性伸缩,就应该换成注册中心分配,用租约把机器 ID 的生命周期和实例绑定起来。


最佳实践

使用 ZooKeeper 或 etcd 进行自动分配,确保唯一性。


下一步

了解了机器 ID 分配后,我们学习优化方案。

👉 下一节:优化方案

发现内容有问题?

告诉我们哪里需要改进。