唯一序列号生成方案

本章将介绍唯一序列号生成方案,为自行生成唯一 ID 的开发者提供帮助。

自增列

自增(auto_increment)是大多数兼容 MySQL 协议的 RDBMS 上列的一种属性,通过配置该属性来使数据库为该列的值自动赋值,用户不需要为该列赋值,该列的值随着表内记录增加会自动增长,并确保唯一性。在大多数场景中,自增列并未拥有业务属性,仅仅代表了这一行数据,即被作为无业务含义的代理主键使用。自增列的局限性在于:自增列只能采用整型字段,所赋的值也只能为整型。假设业务所需要的序列号由字母、数字及其他字符拼接而成,用户将难以通过自增列来获取序列号中所需的数字自增值。

序列(Sequence)

序列是一种数据库对象,应用程序通过调用某个序列可以产生递增的序列值,应用程序可以灵活的使用这个序列值为一张表或多张表赋值,也可以使用序列值进行更复杂的加工,来实现文本和数字的组合,来赋予代理键以一定的跟踪和分类的意义。从 TiDB v4.0 版本开始提供序列功能,详情请参考 CREATE SEQUENCE

类 Snowflake 方案

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

uid-generator 生成的 64 位 ID 结构如下:

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

号段分配方案

号段分配方案可以理解为从数据库批量获取自增 ID。本方案需要一张序列号生成表,每行记录表示一个序列对象。表定义示例如下:

字段名字段类型字段说明
SEQ_NAMEvarchar(128)序列名称,用来区分不同业务
MAX_IDbigint当前序列已被分配出去的最大值
STEPint步长,表示每次分配的号段长度

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

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

文档内容是否有帮助?