分享这篇文章
继续阅读
开发者经常看到 550e8400-e29b-41d4-a716-446655440000 这样的字符串。它通常被当作数据库主键、消息 ID、文件 ID 或外部公开标识。UUID 的核心价值是:在不依赖中央发号器的情况下,让多个系统各自生成足够不容易冲突的 ID。
UUID(Universally Unique Identifier)是一个 128 比特标识符。常见文本格式由 32 个十六进制数字组成,并用 4 个短横线分成 5 段:xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx。
这个格式里包含版本和变种信息:
4。8、9、a 或者 b。128 比特空间共有 2¹²⁸ 种可能,大约是 3.4 × 10³⁸。即使每秒生成 10 亿个 UUID,连续生成 100 年,总量也只有约 3 × 10¹⁸,远小于整个空间。
不同版本的 UUID 解决不同场景。
UUIDv1:时间戳 + MAC 地址 v1 基于时间戳和节点标识生成。它可以按生成时间排序,但可能暴露机器信息和生成时间。
UUIDv2:DCE 安全扩展 v2 是少见的 v1 变体,会包含 POSIX UID/GID 等信息。现代应用很少使用。
UUIDv3:命名空间 + 名称 + MD5 v3 是确定性算法。同一个命名空间和名称会生成同一个 UUID。它适合从 URL、邮箱、文件名等已有唯一值派生 ID,但不应用作安全哈希。
UUIDv4:随机数 v4 是最常见版本。它包含 122 个随机比特。只要随机源可靠,碰撞概率在多数业务规模下可以忽略。
UUIDv5:命名空间 + 名称 + SHA-1 v5 和 v3 思路相同,但使用 SHA-1。需要确定性 UUID 时,v5 通常优于 v3。
UUIDv6:按时间排序的 v1 变体 v6 调整 v1 的字段顺序,让 UUID 更适合按创建时间排序,对 B-Tree 索引更友好。
UUIDv7:Unix 毫秒时间戳 + 随机尾段 v7 把前 48 个比特用于 Unix 毫秒时间戳,后面加入随机比特。它能按时间排序,也比 v4 更适合数据库索引插入。新系统需要 UUID 主键时,可以优先考虑 v7。
UUIDv8:自定义格式 v8 留给应用自定义结构。除非你明确知道字段布局和兼容需求,否则不要随意使用。
v4 UUID 的碰撞风险可以用生日悖论估算。
拥有 122 个随机比特的 v4,要让“至少一次碰撞”的概率达到 50%,大约需要:
n ≈ √(2 × 2¹²² × ln(1 / (1-0.5))) ≈ 2.7 × 10¹⁸(二十七亿亿条 UUID)
如果每秒生成 10 亿个 v4 UUID,也要连续生成约 85 年,才接近 50% 的碰撞概率。多数业务系统的生成规模远低于这个数量。
v3 和 v5 的风险来自哈希碰撞和输入设计。它们适合生成稳定 ID,但不适合承担安全证明。
自增主键和 UUID 各有取舍。选择前先看系统是否需要跨库、离线生成或对外隐藏数量规模。
| 属性维度 | 自增 ID | UUID |
|---|---|---|
| 唯一性作用域 | 单库内唯一 | 跨系统生成 |
| 可天然按生成时间排序 | 是 | 仅 v6 / v7 能够做到 |
| 是否容易被遍历 | 容易 | v4 不容易;v7 暴露时间趋势 |
| 数据库索引插入性能 | 很好 | v4 较差;v7 较好 |
| 是否允许离线生成 | 不行 | 可以 |
| 存储大小 | 4 - 8 字节 | 16 字节 |
如果数据只存在于单个数据库,自增 ID 简单、紧凑、性能好。如果数据可能跨库合并、离线生成、跨服务同步,UUID 更合适。
可以按场景选择:
UUID 让不同服务在没有中央协调的情况下生成 ID。v4 适合随机生成,v5 适合确定性生成,v7 更适合现代数据库主键。选择版本时,不要只看“唯一”,还要看排序、隐私、索引性能和系统边界。