tidb-in-action

6.1.3 高并发的唯一序列号生成方案

应用程序通常使用唯一标识符来确认一行记录。传统解决方案普遍依赖数据库的序列对象(Sequence)来生成唯一标识符中的数字部分。TiDB 4.0 正式支持序列。但是,互联网应用需要处理的数据量巨大且往往呈现爆发式增长,使得应用程序必须在短时间内为大量数据和消息生成唯一标识符。这种场景下,即使有了序列功能,数据库也可能会由于高并发的序列分配请求而出现性能瓶颈。

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

方案一:类 Snowflake 方案

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

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

uid-generator.png

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

方案二:号段分配方案

号段分配方案可以理解为从数据库批量获取自增 ID。本方案需要一张序列号生成表,每行记录表示一个序列对象。表定义示例如下: | 字段名 | 字段类型 | 字段说明 | | :—- | :—— | :—— | | SEQ_NAME | varchar(128) | 序列名称,用来区分不同业务 | | MAX_ID | bigint(20) | 当前序列已被分配出去的最大值 | | STEP | int(11) | 步长,表示每次分配的号段长度 |

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

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