UUID 版本规范详解

14 阅读12分钟

UUID 版本规范详解

目录


概述

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),通常为 89ab(表示标准 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

生成算法

  1. 获取时间戳

    • 使用 UTC 时间,从 1582-10-15 00:00:00(Gregorian 历法起始)开始计算
    • 时间精度为 100 纳秒(0.1 微秒)
    • 时间戳 = (当前时间 - 1582-10-15 00:00:00) / 100 纳秒
  2. 获取时钟序列

    • 14 位时钟序列,用于处理时钟回拨或同一纳秒内生成多个 UUID
    • 如果检测到时钟回拨,时钟序列递增
  3. 获取节点标识符

    • 48 位节点标识符,通常是网络接口的 MAC 地址
    • 如果没有 MAC 地址,使用随机或伪随机值
  4. 组装 UUID

    time_low = 时间戳的低 32time_mid = 时间戳的中间 16time_hi_and_version = (时间戳的高 12 位 << 4) | 0x1000  // 版本 1
    clk_seq_hi_res = (变体 << 6) | (时钟序列的高 6 位)
    clk_seq_low = 时钟序列的低 8node = 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 的基础上,将部分字段替换为本地域标识符:

  1. 时间戳部分:与 v1 相同
  2. 时钟序列:部分或全部替换为本地域标识符
  3. 节点标识符:部分或全部替换为本地域标识符

本地域类型:

  • POSIX_UID:POSIX 用户 ID
  • POSIX_GID:POSIX 组 ID

特点

优点:

  • ✅ 包含用户/组信息,可用于访问控制

缺点:

  • 很少实现:大多数 UUID 库不支持
  • 安全风险:暴露用户/组信息
  • 不推荐使用:RFC 4122 中标记为"保留用于向后兼容"

使用场景

  • 几乎不使用
  • 仅在某些遗留的 DCE 系统中使用

UUID v3 - 基于名称的 MD5

规范

  • RFC 4122 Section 4.3
  • 基于命名空间(Namespace)和名称(Name)的 MD5 哈希生成
  • 版本标识:第 13 个字符为 3
  • 确定性:相同的命名空间和名称总是生成相同的 UUID

生成算法

  1. 定义命名空间 UUID

    • 预定义的命名空间 UUID(如 DNS、URL、OID 等)
    • 或使用任意 UUID 作为命名空间
  2. 准备输入数据

    • 将命名空间 UUID 转换为 16 字节的二进制格式
    • 将名称(字符串)转换为字节序列(UTF-8 编码)
  3. 计算 MD5 哈希

    hash = MD5(命名空间UUID的16字节 || 名称的字节序列)
    
  4. 转换为 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 定义了以下标准命名空间:

  • DNS6ba7b810-9dad-11d1-80b4-00c04fd430c8
  • URL6ba7b811-9dad-11d1-80b4-00c04fd430c8
  • OID6ba7b812-9dad-11d1-80b4-00c04fd430c8
  • X.500 DN6ba7b814-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 版本

生成算法

  1. 生成随机字节

    • 生成 16 个随机字节(128 位)
    • 应使用密码学安全的随机数生成器(CSPRNG)
  2. 设置版本和变体位

    random_bytes[6] = (random_bytes[6] & 0x0F) | 0x40  // 版本 4
    random_bytes[8] = (random_bytes[8] & 0x3F) | 0x80  // 变体
    
  3. 转换为 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 的安全替代方案

生成算法

  1. 定义命名空间 UUID

    • 与 v3 相同,使用标准命名空间或自定义命名空间
  2. 准备输入数据

    • 将命名空间 UUID 转换为 16 字节的二进制格式
    • 将名称转换为字节序列(UTF-8 编码)
  3. 计算 SHA-1 哈希

    hash = SHA1(命名空间UUID的16字节 || 名称的字节序列)
    

    SHA-1 输出 20 字节,取前 16 字节用于 UUID

  4. 转换为 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 相同:

  • DNS6ba7b810-9dad-11d1-80b4-00c04fd430c8
  • URL6ba7b811-9dad-11d1-80b4-00c04fd430c8
  • OID6ba7b812-9dad-11d1-80b4-00c04fd430c8
  • X.500 DN6ba7b814-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 v3UUID v5
哈希算法MD5SHA-1
安全性较低(MD5 已不安全)较高(SHA-1 相对更安全)
性能稍快稍慢
推荐使用❌ 不推荐✅ 推荐

版本对比总结

版本生成方式确定性可排序安全性隐私性推荐度
v1时间戳 + MAC⭐⭐⭐
v2时间戳 + 域ID
v3MD5(命名空间+名称)⭐⭐
v4随机数⭐⭐⭐⭐⭐
v5SHA-1(命名空间+名称)⭐⭐⭐⭐

详细对比表

特性v1v2v3v4v5
基于时间戳
基于随机数
基于哈希
确定性
时间可排序
包含时间信息
包含节点信息
隐私安全
碰撞风险极低极低低(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 存在碰撞风险,不推荐用于安全场景

参考资料

官方规范

相关标准

  • 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: uuid npm 包
  • Go: github.com/google/uuid

在线工具

  • UUID 生成器:www.uuidgenerator.net/
  • UUID 解析器:可以解析 UUID 的版本、变体、时间戳等信息

附录:UUID 变体(Variant)

除了版本号,UUID 还包含变体字段(第 17 个字符的高位):

变体值二进制说明
00xxx保留,向后兼容 NCS
110xxRFC 4122 标准变体(最常用)
2110x保留,Microsoft GUID
3111x保留,未来使用

标准 RFC 4122 UUID 的变体位为 10xx,对应十六进制为 89ab


文档版本: 1.0
最后更新: 2025.11.18