UUID(通用唯一标识符)是 128 位的标识符,无需中央机构即可在空间和时间上保持唯一。它们广泛应用于分布式系统、数据库和 API。但并非所有 UUID 都相同——不同版本在唯一性保证、随机性和确定性方面各有取舍。本文介绍主要 UUID 版本、生成方法、实际用例、安全考虑和常见陷阱。

什么是 UUID?
UUID 是一个 128 位的值,通常表示为 36 字符的字符串,格式为 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx(32 个十六进制数字加 4 个连字符)。标准由 RFC 4122 定义。版本由第 13 个字符(十六进制数字)指示,变体由第 17 个字符指示。例如,在 550e8400-e29b-41d4-a716-446655440000 中,4 表示它是 UUID v4。
UUID 版本
RFC 4122 定义了五个主要版本,外加几个非官方版本(v6、v7、v8)。以下是详细说明:
UUID v1(基于时间)
- 生成:结合当前时间戳(自 1582 年 10 月 15 日以来的 100 纳秒间隔)、时钟序列和节点的 MAC 地址。
- 唯一性:高——时间 + MAC 确保跨机器唯一。
- 确定性:是——给定相同的时间戳和 MAC,生成相同的 UUID。
- 用例:需要按创建时间排序的分布式系统(例如事件日志、版本向量)。
- 陷阱:MAC 地址暴露可能带来隐私风险;时钟偏移可能导致冲突;顺序性可能导致数据库索引碎片。
UUID v4(随机)
- 生成:122 个随机位(6 位固定用于版本/变体)。使用加密安全的随机数生成器(CSPRNG)。
- 唯一性:极高——碰撞概率可忽略不计(2^122 个可能值)。
- 确定性:否。
- 用例:数据库主键、会话标识符、API 令牌、任何需要不可预测性的场景。
- 陷阱:随机源很重要——弱 PRNG 可能导致碰撞;无顺序;比自增整数大。
UUID v3 和 v5(基于名称)
- 生成:使用 MD5(v3)或 SHA-1(v5)哈希命名空间 UUID 和名称字符串,然后截断为 128 位。
- 唯一性:确定性——相同的命名空间 + 名称始终生成相同的 UUID。
- 用例:从规范名称生成一致的标识符(例如 DNS 名称、URL、对象 ID)。
- 陷阱:如果哈希函数有弱点(MD5 被认为不安全),可能发生碰撞;限于 128 位输出。
UUID v6、v7、v8(草案/实验性)
- v6:重新排列 v1 字段使其按时间可排序(字典序)。
- v7:编码 Unix 时间戳(毫秒)加随机位——可排序且随机。
- v8:自由格式,允许自定义数据。
- 用例:数据库友好的 UUID,减少索引碎片(例如,新系统推荐使用 v7)。
对比表
| 版本 | 基础 | 确定性 | 可排序 | 隐私风险 | 碰撞概率 |
|---|---|---|---|---|---|
| v1 | 时间 + MAC | 是 | 是(大致) | 高(MAC 暴露) | 非常低 |
| v4 | 随机 | 否 | 否 | 无 | 可忽略 |
| v3 | MD5 哈希 | 是 | 否 | 无(如果命名空间私密) | 低(MD5 弱点) |
| v5 | SHA-1 哈希 | 是 | 否 | 无 | 非常低 |
| v7 | 时间戳 + 随机 | 否 | 是 | 无 | 可忽略 |
安全与性能考虑
- 随机性质量:始终使用 CSPRNG(例如 Linux 上的
/dev/urandom,Node.js 中的crypto.randomUUID())生成 v4。避免使用Math.random()或rand()——它们可预测,可能导致碰撞或安全问题。 - MAC 地址暴露:UUID v1 泄露节点的 MAC 地址,可用于识别硬件。在云环境中,这可能是一个隐私问题。改用 v4 或 v7。
- 索引碎片:在数据库中,随机 UUID(v4)由于非顺序性可能导致 B 树索引碎片。UUID v7(时间有序)可缓解此问题。
- 存储大小:UUID 为 16 字节(128 位)——大于自增整数(4-8 字节)。考虑使用 binary(16) 或专用 UUID 类型(如果可用)。
完整示例:使用我们的工具生成 UUID
让我们通过我们的 UUID 生成器 逐步生成不同版本的 UUID。
- UUID v4(随机):点击“生成 UUID v4”——工具使用
crypto.getRandomValues()(CSPRNG)生成随机 UUID。示例输出:
9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
- UUID v1(基于时间):点击“生成 UUID v1”——工具结合当前时间戳、时钟序列和随机节点(避免 MAC 暴露)。示例:
c232ab00-5294-11ed-bdc3-0242ac120002
- UUID v5(基于名称):输入命名空间(例如 DNS:
6ba7b810-9dad-11d1-80b4-00c04fd430c8)和名称(例如example.com),然后点击“生成 UUID v5”。工具计算 SHA-1 并截断:
cfbff0d1-9375-5685-968c-48ce8b15ae17
试试我们的 UUID 生成器 查看实时示例。
常见陷阱
- 在面向公众的系统中使用 UUID v1——暴露 MAC 地址,存在隐私风险。
- 为 v4 使用弱随机性——JavaScript 中的
Math.random()不是加密安全的;始终使用crypto.randomUUID()或等效方法。 - 假设 UUID 总是唯一——碰撞概率极低但理论上可能;设计系统优雅处理(例如插入时重试)。
- 在大型数据库中使用 UUID 作为主键而不考虑性能——随机 UUID 导致索引碎片;考虑 v7 或顺序 UUID。
- 使用 UUID v3 而非 v5——MD5 被认为较弱;新实现推荐 SHA-1(v5)。
常见问题
UUID v4 和 v7 有什么区别?
UUID v4 完全随机,而 v7 在前 48 位编码 Unix 时间戳(毫秒),使其按创建时间可排序。v7 减少数据库索引碎片,推荐用于需要时间排序的新系统。
两个 UUID 可能碰撞吗?
是的,但概率极低。对于 UUID v4,有 2^122 个可能值。生成 10 亿个 UUID 的碰撞概率约为 1/2^71。实践中可以忽略,但系统仍应优雅处理重复(例如重试逻辑)。
我应该使用 UUID 作为数据库主键吗?
视情况而定。UUID 提供全局唯一性并避免顺序枚举,但更大(16 字节 vs 整数 4-8 字节),且随机 UUID 可能导致索引碎片。使用 UUID v7 或顺序 UUID 类型可获得更好性能。许多数据库(PostgreSQL、MySQL 8.0+)有原生 UUID 类型。
UUID v1 在公共 API 中使用安全吗?
不推荐——v1 包含生成机器的 MAC 地址,可用于设备跟踪。改用 v4 或 v7。
如何在 Node.js 中生成 UUID?
使用内置的 crypto.randomUUID()(Node.js 14.17+)生成 v4,或使用 uuid npm 包生成其他版本:
const { v4: uuidv4 } = require('uuid');
console.log(uuidv4()); // 例如 '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'