UUID 版本规范详解
目录
- 概述
- UUID 格式
- UUID v1 - 基于时间戳
- UUID v2 - DCE 安全版本
- UUID v3 - 基于名称的 MD5
- UUID v4 - 随机生成
- UUID v5 - 基于名称的 SHA-1
- 版本对比总结
- 使用建议
- 参考资料
概述
UUID(Universally Unique Identifier,通用唯一标识符)是一个 128 位的标识符,用于在分布式系统中唯一标识信息。UUID 由 RFC 4122 标准定义,有多个版本,每个版本有不同的生成算法和用途。
UUID 的基本特征:
- 128 位(16 字节)长度
- 标准格式:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx(32 个十六进制字符,用连字符分隔) - 理论上保证全局唯一性(实际取决于版本和实现)
UUID 格式
标准格式
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
其中:
M表示版本号(1-5)N表示变体(variant),通常为8、9、a或b(表示标准 RFC 4122 变体)
字段结构(128 位)
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | time_hi_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段说明:
time_low(32 位):时间戳的低 32 位time_mid(16 位):时间戳的中间 16 位time_hi_and_version(16 位):高 12 位是时间戳的高位,低 4 位是版本号clk_seq_hi_res(8 位):高 2 位是变体,低 6 位是时钟序列的高位clk_seq_low(8 位):时钟序列的低 8 位node(48 位):节点标识符(通常是 MAC 地址)
UUID v1 - 基于时间戳
规范
- RFC 4122 Section 4.2
- 基于当前时间戳和 MAC 地址生成
- 版本标识:第 13 个字符为
1
生成算法
-
获取时间戳
- 使用 UTC 时间,从 1582-10-15 00:00:00(Gregorian 历法起始)开始计算
- 时间精度为 100 纳秒(0.1 微秒)
- 时间戳 = (当前时间 - 1582-10-15 00:00:00) / 100 纳秒
-
获取时钟序列
- 14 位时钟序列,用于处理时钟回拨或同一纳秒内生成多个 UUID
- 如果检测到时钟回拨,时钟序列递增
-
获取节点标识符
- 48 位节点标识符,通常是网络接口的 MAC 地址
- 如果没有 MAC 地址,使用随机或伪随机值
-
组装 UUID
time_low = 时间戳的低 32 位 time_mid = 时间戳的中间 16 位 time_hi_and_version = (时间戳的高 12 位 << 4) | 0x1000 // 版本 1 clk_seq_hi_res = (变体 << 6) | (时钟序列的高 6 位) clk_seq_low = 时钟序列的低 8 位 node = 48 位节点标识符
特点
优点:
- ✅ 时间可排序:UUID 按生成时间自然排序
- ✅ 包含时间信息:可以从 UUID 中提取生成时间
- ✅ 包含节点信息:可以识别生成 UUID 的机器
- ✅ 性能较好:生成速度快,不需要加密操作
缺点:
- ❌ 隐私风险:暴露 MAC 地址,可能泄露硬件信息
- ❌ 可预测性:基于时间戳,有一定可预测性
- ❌ 时钟依赖:需要系统时钟准确,时钟回拨会影响唯一性
- ❌ MAC 地址依赖:需要有效的网络接口
使用场景
- 需要按时间排序的场景
- 需要追踪生成时间的场景
- 分布式系统中需要识别生成节点的场景(但要注意隐私)
示例
550e8400-e29b-41d4-a716-446655440000
^
版本 1
UUID v2 - DCE 安全版本
规范
- DCE 1.1: Authentication and Security Services
- 基于 UUID v1,但包含本地域标识符(Local Domain Identifier)
- 版本标识:第 13 个字符为
2 - 注意:此版本在实际应用中很少使用
生成算法
UUID v2 在 v1 的基础上,将部分字段替换为本地域标识符:
- 时间戳部分:与 v1 相同
- 时钟序列:部分或全部替换为本地域标识符
- 节点标识符:部分或全部替换为本地域标识符
本地域类型:
POSIX_UID:POSIX 用户 IDPOSIX_GID:POSIX 组 ID
特点
优点:
- ✅ 包含用户/组信息,可用于访问控制
缺点:
- ❌ 很少实现:大多数 UUID 库不支持
- ❌ 安全风险:暴露用户/组信息
- ❌ 不推荐使用:RFC 4122 中标记为"保留用于向后兼容"
使用场景
- 几乎不使用
- 仅在某些遗留的 DCE 系统中使用
UUID v3 - 基于名称的 MD5
规范
- RFC 4122 Section 4.3
- 基于命名空间(Namespace)和名称(Name)的 MD5 哈希生成
- 版本标识:第 13 个字符为
3 - 确定性:相同的命名空间和名称总是生成相同的 UUID
生成算法
-
定义命名空间 UUID
- 预定义的命名空间 UUID(如 DNS、URL、OID 等)
- 或使用任意 UUID 作为命名空间
-
准备输入数据
- 将命名空间 UUID 转换为 16 字节的二进制格式
- 将名称(字符串)转换为字节序列(UTF-8 编码)
-
计算 MD5 哈希
hash = MD5(命名空间UUID的16字节 || 名称的字节序列) -
转换为 UUID
time_low = hash[0:4] // 前 4 字节 time_mid = hash[4:6] // 第 5-6 字节 time_hi_and_version = (hash[6] & 0x0F) | 0x30 // 版本 3 clk_seq_hi_res = (hash[8] & 0x3F) | 0x80 // 变体 clk_seq_low = hash[9] node = hash[10:16] // 后 6 字节
标准命名空间
RFC 4122 定义了以下标准命名空间:
- DNS:
6ba7b810-9dad-11d1-80b4-00c04fd430c8 - URL:
6ba7b811-9dad-11d1-80b4-00c04fd430c8 - OID:
6ba7b812-9dad-11d1-80b4-00c04fd430c8 - X.500 DN:
6ba7b814-9dad-11d1-80b4-00c04fd430c8
特点
优点:
- ✅ 确定性:相同输入总是产生相同 UUID
- ✅ 可重现:可以从名称推导出 UUID
- ✅ 命名空间隔离:不同命名空间的相同名称产生不同 UUID
- ✅ 无需随机数生成器
缺点:
- ❌ MD5 安全性:MD5 已被认为不安全(碰撞风险)
- ❌ 不可随机:完全可预测
- ❌ 不推荐用于安全场景
使用场景
- 需要从名称生成稳定 UUID 的场景
- 数据迁移和一致性要求
- 非安全敏感的场景
示例
import uuid
# 使用 DNS 命名空间
namespace_dns = uuid.NAMESPACE_DNS
name = "example.com"
uuid_v3 = uuid.uuid3(namespace_dns, name)
# 结果:6ba7b810-9dad-11d1-80b4-00c04fd430c8 (对于 "example.com")
UUID v4 - 随机生成
规范
- RFC 4122 Section 4.4
- 完全基于随机数或伪随机数生成
- 版本标识:第 13 个字符为
4 - 最常用的 UUID 版本
生成算法
-
生成随机字节
- 生成 16 个随机字节(128 位)
- 应使用密码学安全的随机数生成器(CSPRNG)
-
设置版本和变体位
random_bytes[6] = (random_bytes[6] & 0x0F) | 0x40 // 版本 4 random_bytes[8] = (random_bytes[8] & 0x3F) | 0x80 // 变体 -
转换为 UUID 格式
- 直接使用随机字节作为 UUID 的各个字段
特点
优点:
- ✅ 完全随机:不可预测,安全性高
- ✅ 无隐私泄露:不包含任何可识别信息
- ✅ 简单高效:生成算法简单
- ✅ 广泛支持:所有 UUID 库都支持
- ✅ 推荐使用:大多数场景的首选
缺点:
- ❌ 不可排序:无法按时间排序
- ❌ 不可重现:每次生成都不同
- ❌ 需要随机数生成器:依赖 CSPRNG 质量
使用场景
- 通用唯一标识符:大多数应用场景
- 安全敏感场景:需要不可预测的标识符
- 数据库主键:分布式系统中的主键
- 会话 ID:Web 应用的会话标识
示例
import uuid
uuid_v4 = uuid.uuid4()
# 示例输出:9b4c5d6e-7f8a-4b3c-2d1e-0f9a8b7c6d5e
# ^
# 版本 4
碰撞概率
- 128 位空间,共有 2^128 ≈ 3.4 × 10^38 种可能
- 生成 10 亿个 UUID,碰撞概率约为 2.71 × 10^-18(几乎为零)
- 需要生成约 2.71 × 10^18 个 UUID 才有 50% 的碰撞概率
UUID v5 - 基于名称的 SHA-1
规范
- RFC 4122 Section 4.3
- 基于命名空间和名称的 SHA-1 哈希生成
- 版本标识:第 13 个字符为
5 - 确定性:相同的命名空间和名称总是生成相同的 UUID
- v3 的安全替代方案
生成算法
-
定义命名空间 UUID
- 与 v3 相同,使用标准命名空间或自定义命名空间
-
准备输入数据
- 将命名空间 UUID 转换为 16 字节的二进制格式
- 将名称转换为字节序列(UTF-8 编码)
-
计算 SHA-1 哈希
hash = SHA1(命名空间UUID的16字节 || 名称的字节序列)SHA-1 输出 20 字节,取前 16 字节用于 UUID
-
转换为 UUID
time_low = hash[0:4] // 前 4 字节 time_mid = hash[4:6] // 第 5-6 字节 time_hi_and_version = (hash[6] & 0x0F) | 0x50 // 版本 5 clk_seq_hi_res = (hash[8] & 0x3F) | 0x80 // 变体 clk_seq_low = hash[9] node = hash[10:16] // 第 11-16 字节
标准命名空间
与 v3 相同:
- DNS:
6ba7b810-9dad-11d1-80b4-00c04fd430c8 - URL:
6ba7b811-9dad-11d1-80b4-00c04fd430c8 - OID:
6ba7b812-9dad-11d1-80b4-00c04fd430c8 - X.500 DN:
6ba7b814-9dad-11d1-80b4-00c04fd430c8
特点
优点:
- ✅ 确定性:相同输入总是产生相同 UUID
- ✅ 安全性更好:SHA-1 比 MD5 更安全(虽然 SHA-1 也有已知弱点,但比 MD5 好)
- ✅ 可重现:可以从名称推导出 UUID
- ✅ 命名空间隔离:不同命名空间的相同名称产生不同 UUID
- ✅ 推荐用于基于名称的场景
缺点:
- ❌ 不可随机:完全可预测
- ❌ 计算开销:SHA-1 比 MD5 稍慢(但差异很小)
- ❌ SHA-1 安全性:SHA-1 已被认为存在安全风险(但对于 UUID 生成通常足够)
使用场景
- 需要从名称生成稳定 UUID 的场景
- 需要比 v3 更安全的基于名称的 UUID
- 数据迁移和一致性要求
- 资源标识符(如 URL 到 UUID 的映射)
示例
import uuid
# 使用 URL 命名空间
namespace_url = uuid.NAMESPACE_URL
name = "https://example.com/user/123"
uuid_v5 = uuid.uuid5(namespace_url, name)
# 结果:对于相同的 URL,总是生成相同的 UUID
v3 vs v5 对比
| 特性 | UUID v3 | UUID v5 |
|---|---|---|
| 哈希算法 | MD5 | SHA-1 |
| 安全性 | 较低(MD5 已不安全) | 较高(SHA-1 相对更安全) |
| 性能 | 稍快 | 稍慢 |
| 推荐使用 | ❌ 不推荐 | ✅ 推荐 |
版本对比总结
| 版本 | 生成方式 | 确定性 | 可排序 | 安全性 | 隐私性 | 推荐度 |
|---|---|---|---|---|---|---|
| v1 | 时间戳 + MAC | ❌ | ✅ | 中 | ❌ | ⭐⭐⭐ |
| v2 | 时间戳 + 域ID | ❌ | ✅ | 低 | ❌ | ❌ |
| v3 | MD5(命名空间+名称) | ✅ | ❌ | 低 | ✅ | ⭐⭐ |
| v4 | 随机数 | ❌ | ❌ | 高 | ✅ | ⭐⭐⭐⭐⭐ |
| v5 | SHA-1(命名空间+名称) | ✅ | ❌ | 中 | ✅ | ⭐⭐⭐⭐ |
详细对比表
| 特性 | v1 | v2 | v3 | v4 | v5 |
|---|---|---|---|---|---|
| 基于时间戳 | ✅ | ✅ | ❌ | ❌ | ❌ |
| 基于随机数 | ❌ | ❌ | ❌ | ✅ | ❌ |
| 基于哈希 | ❌ | ❌ | ✅ | ❌ | ✅ |
| 确定性 | ❌ | ❌ | ✅ | ❌ | ✅ |
| 时间可排序 | ✅ | ✅ | ❌ | ❌ | ❌ |
| 包含时间信息 | ✅ | ✅ | ❌ | ❌ | ❌ |
| 包含节点信息 | ✅ | ✅ | ❌ | ❌ | ❌ |
| 隐私安全 | ❌ | ❌ | ✅ | ✅ | ✅ |
| 碰撞风险 | 极低 | 极低 | 低(MD5) | 极低 | 低(SHA-1) |
| 实现支持 | 广泛 | 很少 | 广泛 | 广泛 | 广泛 |
使用建议
选择指南
🎯 选择 UUID v4(随机)如果:
- 需要通用唯一标识符
- 不需要时间排序
- 不需要从名称推导
- 需要最高安全性
- 这是大多数场景的默认选择
🎯 选择 UUID v5(基于名称)如果:
- 需要从名称生成稳定的 UUID
- 需要可重现的标识符
- 需要命名空间隔离
- 例如:将 URL、域名、用户名等转换为 UUID
🎯 选择 UUID v1(基于时间)如果:
- 需要按时间排序
- 需要追踪生成时间
- 不担心隐私泄露
- 例如:日志记录、时间序列数据
🎯 避免使用:
- UUID v2:几乎不被支持,不推荐
- UUID v3:如果可能,使用 v5 替代(更安全)
实际应用示例
数据库主键
# 推荐:使用 v4
primary_key = uuid.uuid4()
资源标识符(URL 到 UUID)
# 推荐:使用 v5
resource_uuid = uuid.uuid5(uuid.NAMESPACE_URL, "https://api.example.com/users/123")
会话 ID
# 推荐:使用 v4(安全随机)
session_id = uuid.uuid4()
时间序列数据
# 可选:使用 v1(如果需要排序)
timestamp_uuid = uuid.uuid1()
性能考虑
- v4(随机):最快,只需生成随机数
- v1(时间戳):较快,需要获取时间和 MAC 地址
- v3/v5(哈希):较慢,需要计算哈希,但差异很小
安全考虑
- v4:最安全,完全不可预测
- v5:对于基于名称的场景足够安全
- v1:可能泄露 MAC 地址和时间信息
- v3:MD5 存在碰撞风险,不推荐用于安全场景
参考资料
官方规范
- RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace
- DCE 1.1: Authentication and Security Services
相关标准
- ISO/IEC 11578:1996: Information technology – Open Systems Interconnection – Remote Procedure Call (RPC)
- ITU-T Rec. X.667: Information technology – Procedures for the operation of object identifier registration authorities
实现库
- Python:
uuid模块(标准库) - Java:
java.util.UUID - C++: Boost.UUID, libuuid
- JavaScript:
uuidnpm 包 - Go:
github.com/google/uuid
在线工具
- UUID 生成器:www.uuidgenerator.net/
- UUID 解析器:可以解析 UUID 的版本、变体、时间戳等信息
附录:UUID 变体(Variant)
除了版本号,UUID 还包含变体字段(第 17 个字符的高位):
| 变体值 | 二进制 | 说明 |
|---|---|---|
| 0 | 0xxx | 保留,向后兼容 NCS |
| 1 | 10xx | RFC 4122 标准变体(最常用) |
| 2 | 110x | 保留,Microsoft GUID |
| 3 | 111x | 保留,未来使用 |
标准 RFC 4122 UUID 的变体位为 10xx,对应十六进制为 8、9、a 或 b。
文档版本: 1.0
最后更新: 2025.11.18