4. 规范
4.1. 格式
UUID 格式为 16 个八位字节 (octets). 下面指定的八位字节 8 variant 字段中的某些位决定了更细的结构.
4.1.1. Variant
variant 字段决定 UUID 的布局. 也就是说, UUID 中所有其他位的解释都取决于 variant 字段中位的设置. variant 字段由 UUID 的八位字节 8 中数量可变的最高有效位组成.
下表列出了 variant 字段的内容, 其中字母 "x" 表示 "don't-care" 值.
| Msb0 | Msb1 | Msb2 | 描述 |
|---|---|---|---|
| 0 | x | x | 保留, NCS 向后兼容性 |
| 1 | 0 | x | 本文档指定的 variant |
| 1 | 1 | 0 | 保留, Microsoft Corporation 向后兼容性 |
| 1 | 1 | 1 | 保留供将来定义 |
4.1.2. 布局和字节序
为了尽量减少关于八位字节内位分配的混淆, UUID 记录定义只按照由整数个八位字节组成的字段来定义. 字段按最高有效字段在前的顺序呈现.
| 字段 | 数据类型 | 八位字节编号 | 说明 |
|---|---|---|---|
| time_low | unsigned 32 bit integer | 0-3 | 时间戳的低位字段 |
| time_mid | unsigned 16 bit integer | 4-5 | 时间戳的中间字段 |
| time_hi_and_version | unsigned 16 bit integer | 6-7 | 与版本号复用的时间戳高位字段 |
| clock_seq_hi_and_reserved | unsigned 8 bit integer | 8 | 与 variant 复用的时钟序列高位字段 |
| clock_seq_low | unsigned 8 bit integer | 9 | 时钟序列的低位字段 |
| node | unsigned 48 bit integer | 10-15 | 空间唯一的节点标识符 |
UUID 结构 (128 bits):
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) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4.1.3. 版本
版本号位于时间戳的最高有效 4 位中 (time_hi_and_version 字段的 bits 4 through 7).
下表列出了此 UUID variant 当前已定义的版本:
| Msb0-3 | Version | 描述 |
|---|---|---|
| 0001 | 1 | 本文档指定的基于时间的版本 |
| 0010 | 2 | DCE Security 版本, 带有嵌入式 POSIX UIDs |
| 0011 | 3 | 本文档指定的使用 MD5 哈希的基于名称的版本 |
| 0100 | 4 | 本文档指定的随机或伪随机生成版本 |
| 0101 | 5 | 本文档指定的使用 SHA-1 哈希的基于名称的版本 |
4.1.4. 时间戳
时间戳是一个 60-bit 值. 对于 UUID version 1, 它由协调世界时 (Coordinated Universal Time, UTC) 表示, 计为自 1582 年 10 月 15 日 00:00:00.00 (基督教历法改用 Gregorian calendar 的日期) 以来的 100-nanosecond 间隔数.
对于 UUID version 3 或 5, 时间戳是按照 Section 4.3 所述由名称构造的 60-bit 值.
对于 UUID version 4, 时间戳是按照 Section 4.4 所述随机或伪随机生成的 60-bit 值.
4.1.5. 时钟序列
对于 UUID version 1, 时钟序列用于帮助避免在时钟被向后调回或节点 ID 发生变化时可能出现的重复.
时钟序列必须最初 (即在系统生命周期中一次) 初始化为随机数, 以尽量降低系统之间的相关性.
对于 UUID version 3 或 5, 时钟序列是按照 Section 4.3 所述由名称构造的 14-bit 值.
对于 UUID version 4, 时钟序列是随机或伪随机生成的 14-bit 值.
4.1.6. 节点
对于 UUID version 1, node 字段由 IEEE 802 MAC 地址组成, 通常是主机地址. 对于具有多个 IEEE 802 地址的系统, 可以使用任何可用地址.
对于 UUID version 3 或 5, node 字段是按照 Section 4.3 所述由名称构造的 48-bit 值.
对于 UUID version 4, node 字段是随机或伪随机生成的 48-bit 值.
4.1.7. Nil UUID
nil UUID 是一种特殊形式的 UUID, 指定为所有 128 位均设置为零:
00000000-0000-0000-0000-000000000000
4.2. 创建基于时间的 UUID 的算法
4.2.1. 基本算法
生成基于时间的 UUID 的基本算法:
- 获取系统范围的全局锁
- 读取当前时间
- 获取当前节点 ID
- 如果节点 ID 自上次生成 UUID 后已经改变, 则将时钟序列设置为随机值
- 如果当前时间早于上一个时间戳, 则递增时钟序列
- 保存时间戳和节点 ID
- 释放全局锁
- 使用时间戳, 时钟序列和节点 ID 格式化 UUID
4.2.2. 生成细节
时间戳: 时间戳是由系统时间构造的 60-bit 值. 时间戳分辨率为 100 nanoseconds.
时钟序列: 时钟序列最初设置为随机值. 每当时钟向后移动或节点 ID 改变时, 它都会递增.
节点 ID: 节点 ID 通常是 IEEE 802 MAC 地址.
4.3. 创建基于名称的 UUID 的算法
创建基于名称的 UUID (version 3 或 version 5) 的算法:
- 分配一个 UUID, 作为从该名称空间中的名称生成所有 UUID 时使用的 "name space ID"
- 选择 MD5 (version 3) 或 SHA-1 (version 5) 作为哈希算法
- 将名称转换为规范的八位字节序列
- 计算名称空间 ID 与名称拼接后的哈希
- 将 octets zero through 15 设置为该哈希的 octets zero through fifteen
- 将 octet 6 的四个最高有效位 (bits 12 through 15) 设置为适当的版本号
- 将 octet 8 的两个最高有效位 (bits 6 and 7) 分别设置为零和一
4.4. 从真随机数或伪随机数创建 UUID 的算法
version 4 UUID 用于从真随机数或伪随机数生成 UUID.
算法如下:
- 将所有位设置为随机 (或伪随机) 选择的值
- 将 octet 6 的四个最高有效位 (bits 12 through 15) 设置为 4-bit 版本号 (0100 binary)
- 将 octet 8 的两个最高有效位 (bits 6 and 7) 分别设置为零和一
4.5. 不标识主机的节点 ID
本节描述生成不标识主机的节点 ID 的替代方案:
-
随机节点 ID: 将节点 ID 的第一个 octet 的最低有效位设置为一 (multicast bit). 这会将 UUID 标记为不是基于真实 MAC 地址.
-
持久随机节点 ID: 生成一次随机节点 ID 并存储以供重用. 这在保持隐私的同时提供跨重启的一致性.