1. 引言
软件 ID 是计算机系统中的重要概念,它用于标识不同的数据实体和交互过程。ID 生成方案是指用于生成唯一标识符(ID)的算法或方法。这些标识符通常用于唯一标识数据库中的记录、消息队列中的消息、分布式系统中的节点等。
一个好的 ID 生成方案应该能够生成唯一的 ID,并且应该是高效的,在处理大量数据时不会影响性能。
理想的唯一 ID 有以下特性:
- 唯一性:生成的 ID 全局唯一,在特定范围内冲突概率极小
- 有序性:生成的 ID 按某种规则有序,便于插入及排序
- 可用性:可保证高并发下的可用性
- 自主性:分布式环境下不依赖中心认证即可自行生成 ID
- 安全性:不暴露系统和业务的信息
2. 常用的 ID 生成方案
★ 介绍一款能够查看各种 ID 介绍,并且能生成 ID 的工具:ID Master ★
2.1. 数据库自增 ID
数据库自增 ID 是一种常见的唯一标识符生成方案,依赖于所使用数据库的本身机制,不赘述了。
2.2. UUID
UUID 常用的是版本 4。有很多讨论是关于数据库自增 ID 好还是 UUID 好。
这样的讨论很多,我个人觉得虽然有各种缺点,但是 UUID 是一个比数据库自增 ID 更好的选择。
2.3. Twitter 雪花(Snowflake)算法
Snowflake 是由 Twitter 开发的一种分布式 ID 生成算法,可以保证 ID 的唯一性和足够的可排序性。Snowflake 的 ID 格式为 64 位整数,其中第 1 位为符号位,接下来的 41 位为时间戳,10 位为节点 ID,12 位为序列号。
它具有以下特点:
- 全局唯一性:在不同的机器上生成 Snowflake ID,几乎不可能出现重复的情况。
- 时间有序性:Snowflake ID 中包含了时间戳信息,因此可以根据 Snowflake ID 的大小来推断生成时间的先后顺序。
- 可读性:Snowflake ID 采用了固定的 64 位二进制格式,使得其可以被人类较易读懂。
- 分布式生成:Snowflake ID 可以支持分布式系统,每个节点都可以生成唯一的标识符,从而避免了单点故障。
- 高性能:Snowflake ID 的生成过程非常快速,因为它是纯内存操作。同时,Snowflake ID 的长度为 64 位,比许多其他唯一标识符更短,而且更加紧凑。
3. 一些较新的方案
这个才是这篇文章的重点。
较新的方案一般有如下特点:
- 本地生成,不依赖于分布式方案
- 选择字符串类型
- 在满足唯一性的前提下,ID 长度尽量短
- 时间有序
3.1. UUID v678
IETF 在起草新的 UUID 格式,也是顺应的应用的趋势。
- v6 的字段兼容 v1,只是字段顺序调整了,对 DB 局部性更友好。
- v7 是 Unix 时间戳和随机数
- v8 直接开放字段定义,只有 ver 和 var 字段有要求,其他位置完全由实现定义。
其中看到两个趋势:
- 性能:v6 和 v7 都有考虑可排序性,解决 UUID 应用时最常遇到的数据库性能问题
- 可自定义性:应用需求前变万化,一个标准解决不了全部问题,市面上有了各种各样的 ID 生成方案,于是有了 v8
3.2. ULID
ULID(Universally Unique Lexicographically Sortable Identifier)是一种基于时间戳的唯一标识符,具有以下特点:
- 全局唯一性:在不同的机器上生成 ULID,几乎不可能出现重复的情况。
- 时间有序性:ULID 中包含了时间戳信息,因此可以根据 ULID 的大小来推断生成时间的先后顺序。
- 可读性:ULID 使用了基于 Crockford’s Base32 编码的字符集,使得其可以被人类较易读懂。
- 长度适中:ULID 的长度为 26 个字符,比许多其他唯一标识符更短,而且更加紧凑。
高位 48 位时间+低位 80 位随机数,使用 base32 编码为 26 个字符的字符串。
3.3. Nano ID
Nano ID 是一种轻量级、高性能的 ID 生成器,采用了类似 Twitter 的 Snowflake 算法。Nano ID 的长度为 21 个字符,其中 15 个字符用于表示时间戳,6 个字符用于生成随机数,可以保证 ID 的唯一性和足够的随机性。Nano ID 适用于高并发环境下的 ID 生成,例如 URL 缩短服务等。但是,Nano ID 不适用于需要支持排序或时间相关操作的场景。
3.4. KSUID
来自 CDP 厂商 Segment。
高位 20 位时间+低位 128 位随机数,使用 base62 编码为 27 个字符的字符串。
3.5. TSID
时间有序的 64 位整数,使用 base32 编码为 13 个字符的字符串。
3.6. Cuid2
通过多轮迭代计算,生成指定长度的Base36编码字符串,主打一个安全,但是计算速度慢。时间无序。
4. 如何选择合适的 ID 生成方案
方案 | 数字位数 | 字符串长度 | 时间有序 |
---|---|---|---|
自增长 ID | 64 | 1-20 | 是 |
UUID | 128 | 36 | 取决于版本 |
Snowflake | 64 | 1-19 | 是 |
ULID | 128 | 26 | 是 |
Nano ID | 64 | 21 | 否 |
KSUID | 160 | 27 | 是 |
TSID | 64 | 13 | 是 |
Cuid2 | 可变 | 可变 | 否 |
选择哪种 ID 生成方案取决于应用程序的需求和预期的负载。
目前我选择的是 ULID。为什么不选 KSUID?虽然随机数很多(避免碰撞),但是它的时间精度不够。