snowflake 是什么
snowflake 单词原意为雪花,是 twitter 开源的一种分布式 ID 生成算法。该算法可以保证在不借助第三方服务或者说工具的情况下毫秒单位符号,在多台机器上持续生成保证唯一性的 64 位整型 ID。
snowflake ID 的组成
snowflake 将 ID 的 64 位划分为四块区域,分别填入的是当前服务实例的数据中心 ID,节点 ID,时间戳,以及相同时间戳下的递增序号。
以下是 snowflake 原始算法中,各字段的顺序以及所占的位数:
ID组成图
小提示,在生产环境,使用 snowflake 的思想生成分布式 ID 时,这些字段所占的位数可以根据自身业务灵活调整。本文如无特殊说明,都是针对 snowflake 原始算法进行讲解。
数据中心 ID 和节点 ID
不同的服务实例间,使用不同的数据中心 ID 和节点 ID,可以保证生成的 ID 不重复。
从该算法使用数据中心 ID 加节点 ID(而不是单个服务实例 ID)的方式决定服务实例的唯一性,也可以看出,该算法设计之初是一个非常面向具体业务场景的算法。
数据中心 ID 和节点 ID 分别占 5 位。即整个系统最多可以有 32 个数据中心,每个数据中心最多可以有 32 个节点。为什么数据中心 ID 和节点 ID 是 5 位?额,应该也是 twitter 根据当时的业务拍脑袋拍的。
那么数据中心 ID 和节点 ID 怎么生成呢?这点不由 snowflake 负责,也即这两个 ID 在多个服务实例之间不重复是由 snowflake 的调用方保证的。比如一种简单的方式是直接使用静态配置,这种方式适用于节点数量比较少且相对固定的情况下。
时间戳
如前文图中展示,snowflake 使用 42 位存储时间戳。
我们平时所说的 UNIX 时间戳,指的是从 1970 年 1 月 1 号 0 点到现在所经过的时间。如果单位是毫秒,需要使用 64 位整型存储。
由于在 snowflake 算法中,只需要保证时间戳随时间递增即可,所以 snowflake 中的时间戳是使用 UNIX 时间戳减去一个基准时间,这个基准时间在原版代码中是 1288834974657毫秒单位符号,也即2010/11/4 9:42:54.657。你也可以换种方式理解,即从 2010 年 11 月 4 号 xxx 这个基准时间点到现在所经过的时间。
减去自定义的基准时间后,时间戳比 UNIX 时间戳小了很多,snowflake 使用得到的时间戳的低 42 位作为 ID 的一部分(即 ID 的高 42 位)。如下图所示:
时间戳取值图时间戳可能存在的问题
首先项目加盟,时间戳随着系统时间增长,当时间戳的第 42 位增长到 1 时,ID 的最高位也将变为 1。由于 snowflake 默认使用有符号 64 位整型,最高位为符号位,这将导致生成的 ID 变为负数。
通过如下公式(1