🆔
← 返回教程列表

什么是 UUID?通用唯一标识符完全指南

· 标签: uuid, guid, database, primary-key, uuid-v7

UUID(Universally Unique Identifier)是一个 128 位的标签,用于唯一标识信息。使用 UUID v4 两次生成同一个 UUID 的概率低到令人咋舌——在生成约 2.71 乘以 10 的 18 次方个 UUID 后,碰撞概率仅为 50%。换句话说,UUID 让你可以在没有中央协调机构的情况下,在任何地方、任何时间生成全球唯一的标识符。

UUID 的结构解析

标准的 UUID 格式为 32 个十六进制数字,用连字符分隔成 5 组:550e8400-e29b-41d4-a716-446655440000。这个字符串并非随意排列,而是有严格的内部结构。时间低位(time_low)占据前 8 位,时间中位(time_mid)占据接下来的 4 位,版本和时间高位(version & time_high)占 4 位,变体和时钟序列(variant & clock_seq)占 4 位,最后的节点 ID(node)占 12 位。其中,第 13 位的版本半字节指示了生成算法:1 代表 v1,4 代表 v4,7 代表 v7。

各版本对比与应用场景

UUID v1 通过结合 MAC 地址和时间戳来生成 UUID,保证了时空上的唯一性,但会泄露生成机器的 MAC 地址和生成时间,因此在注重隐私的场景中不受欢迎。UUID v4 使用随机数生成器,简单直接,不泄露任何信息,适合绝大多数不需要排序的场景,如会话 ID、文件名、临时标识符等。UUID v7 是 2024 年新增的版本,在开头包含一个 48 位的毫秒级时间戳,既保留了全球唯一性和无需协调的优势,又解决了 v4 在数据库索引场景下的性能问题。

UUID vs 自增 ID

这是软件开发中一个经典的架构选择。自增 ID 简单、紧凑、天然有序,在单数据库环境中表现出色。但一旦进入分布式场景——多数据库实例、客户端生成 ID、数据合并——自增 ID 就暴露了严重缺陷:不同节点生成的 ID 会冲突,扩容需要复杂的方案。UUID 则天然适合分布式系统,任何节点都能在不与其他节点通信的情况下生成全局唯一的 ID。代价是存储空间(128 比特 vs 通常 32 或 64 比特的自增 ID)和索引性能,但 UUID v7 已经基本解决了索引性能问题。

UUID 在数据库中的实际表现

在 PostgreSQL 中,UUID 是原生支持的数据类型,比将其存储为文本更高效。MySQL 8.0 也新增了 UUID_TO_BIN() 函数来优化 UUID 的二进制存储。使用 UUID v4 作为 B-tree 主键时,由于值是随机的,每次插入新记录都可能导致 B-tree 页面分裂,产生碎片化——这是数据库写入性能最大的敌人。UUID v7 通过将时间戳前置,使得新生成的值大致上是自然递增的(受精度限制,同一毫秒内的值可能乱序),从而将页面分裂和碎片化的影响降至最小。在分布式数据库中,如 CockroachDB 和 TiDB,甚至已经原生内置了类似 UUID v7 的时间有序 ID 生成功能。

分布式系统中的 UUID

在微服务架构、事件溯源系统和 CQRS 架构中,UUID 的使用非常广泛。事件 ID 通常使用 UUID 来保证在多个服务、多个可伸缩副本之间的事件 ID 不可变且不冲突。物联网设备在离线环境中生成的数据记录也需要 UUID 来保证即使重新上线时也不会产生冲突。在多区域多主数据库集群中,UUID 是解决写入冲突的必要手段。我们的免费 UUID 生成器支持批量生成,非常适合在这些场景中使用。

生成器的工作原理

现代浏览器和 Node.js 都提供了 crypto.randomUUID() API,可以直接生成符合标准的 UUID v4。新版运行时也开始支持 crypto.randomUUID({ version: 7 }) 来生成 UUID v7。在低于这些 API 可用版本的环境中,可以通过组合 crypto.getRandomValues() 和时间戳手动构造 UUID。无论哪种方式,底层的随机源都是密码学安全的随机数生成器,而不是简单的伪随机数发生器。我们的 UUID 生成器在浏览器中封装了这些 API,提供一键生成和批量生成功能。

UUID 的唯一性是否绝对可靠

虽然数学上 UUID v4 的碰撞概率不为零,但把这个概率放在宇宙的尺度上看,你可以认为它在实际中是不可能发生的。即使每秒生成 10 亿个 UUID v4,也需要 85 年才会有 50% 的概率出现一次碰撞。相比之下,你更可能遭遇硬件错误、网络数据损坏或软件 Bug 导致的 ID 冲突。对于那些需要绝对无碰撞的应用,可以使用 UUID v1(保证 MAC 地址和时钟唯一)或在 UUID v4 的上层结合应用特定的去重机制。

编码与传输格式

UUID 的标准文本表示是 32 个十六进制数字,按 8-4-4-4-12 的格式使用连字符分组。在带宽紧张的场景中,也可以将 UUID 编码为 Base64 或二进制形式。标准的 36 个字符的 UUID 可以压缩为 22 个字符的 Base64 表示,节省约 40% 的传输带宽。在 Protobuf 或 MessagePack 等二进制序列化格式中,通常直接存储 128 比特的二进制表示,完全省去字符编码的开销。