本节将介绍两种高性能的序列号生成方案。

    Snowflake 是 Twitter 提出的分布式 ID 生成方案。目前有多种实现,较流行的是百度的 uid-generator 和美团的 leaf。下面以 uid-generator 为例展开说明。

    • delta seconds:默认 28 位。当前时间,表示为相对于某个预设时间基点 (默认 “2016-05-20”) 的增量值,单位为秒。28 位最多可支持约 8.7 年。
    • worker node id:默认 22 位。表示机器 id,通常在应用程序进程启动时从一个集中式的 ID 生成器取得。常见的集中式 ID 生成器是数据库自增列或者 Zookeeper。默认分配策略为用后即弃,进程重启时会重新获取一个新的 worker node id,22 位最多可支持约 420 万次启动。

    使用类 Snowflake 方案时需要注意几个问题:

    • delta seconds 完全本地生成,强依赖机器时钟。如果发生时钟回拨, 会导致发号重复或者服务会处于不可用状态。
    • 可根据数据预期寿命调整 delta seconds 位数, 一般在 28 位至 44 位之间。
    • worker node id 位数有限,对应数值不超过 500 万。 如果使用 TiDB 的自增列实现 worker node id,每次 TiDB 实例的重启都会让自增列返回值增加至少 3 万,这样最多 500 / 3 = 166 次实例重启后,自增列返回值就比 worker node id 可接受的最大值要大。这时就不能直接使用这个过大的值,需要清空自增列所在的表,把自增列值重置为零,也可以在 Snowflake 实现层解决这个问题。

    方案二:号段分配方案

    应用程序每次按配置好的步长获取一段序列号,并同时更新数据库以持久化保存当前序列已被分配出去的最大值,然后在应用程序内存中即可完成序列号加工及分配动作。待一段号码耗尽之后,应用程序才会去获取新的号段,这样就有效降低了数据库写入压力。实际使用过程中,还可以适度调节步长以控制数据库记录的更新频度。

    最后,需要注意的是,上述两种方案生成的 ID 都不够随机,不适合直接作为 TiDB 表的主键。实际使用过程中可以对生成的ID进行位反转(bit-reverse)后得到一个较为随机的新 ID。