958 字
5 分钟
[programming] UUID 的实现逻辑

引言#

在分布式系统中,为每一个资源生成一个全局唯一的标识符(ID)是基础且关键的需求。UUID(Universally Unique Identifier,通用唯一识别码)作为一种无需中央授权机构即可产生唯一标识的标准,被广泛应用于数据库主键、会话标识和文件命名等场景。

然而,128 位的 UUID 究竟是如何构成的?它真的能保证永远不重复吗?本文将深入其底层实现逻辑。

UUID 的基本构造 (RFC 4122)#

UUID 的标准定义在 RFC 4122 中。它是一个 128 位的二进制数,通常以 32 个十六进制数字表示,并由四个连字符分隔成五组:8-4-4-4-12

128 位的比特流#

虽然我们在代码中常看到字符串形式,但 UUID 的本质是 16 个字节。例如: 550e8400-e29b-41d4-a716-446655440000

变体 (Variant) 与版本 (Version)#

UUID 的结构中包含两个特殊的字段,用于标识其类型:

  • Variant (变体):决定了 UUID 的布局。现代绝大多数 UUID 都是 RFC 4122 定义的变体。
  • Version (版本):位于第 13 个十六进制位(即 48-51 位),标识了该 UUID 是如何生成的(V1 到 V8)。

常见版本的底层实现机制#

UUID V1:基于时间与 MAC 地址#

V1 是最早的版本之一,其生成逻辑如下:

  1. 时间戳:占 60 位,记录自 1582 年 10 月 15 日(格列高利历开始)以来的 100 纳秒间隔。
  2. 时钟序列:占 14 位,用于处理系统时钟回拨或在同一时间戳内生成多个 UUID 的情况。
  3. 节点 ID:占 48 位,通常是主机的 MAC 地址
TIP

V1 保证了全局唯一(因为 MAC 地址唯一且时间戳递增),但也可能暴露生成者的硬件隐私(MAC 地址)和生成时间。

UUID V4:基于伪随机数#

V4 是目前应用最广泛的版本。除了 6 位用于标识版本和变体外,其余 122 位全部是随机生成的

  • 优点:极难被猜测,且不包含敏感信息。
  • 缺点:完全无序,作为数据库主键时,会导致 B+ 树索引频繁分裂,影响性能。

UUID V7:兼顾随机性与时间有序 (现代推荐)#

作为 RFC 9562 的新成员,V7 正在成为分布式系统的新宠:

  1. 前 48 位:Unix 时间戳(毫秒级)。
  2. 后 74 位:随机数。
  • 核心优势:它是 时间有序(Monotonic) 的。这使得它非常适合作为数据库索引,同时具备足够的熵来保证唯一性。

UUID 真的会重复吗?#

这是一个概率学问题。以最常用的 UUID V4 为例。

碰撞概率的直观类比#

要在 UUID V4 中达到 50% 的碰撞概率,需要生成约 2.31 × 10¹⁸ 个 UUID。

  • 如果每秒生成 10 亿个 UUID,连续生成 73 年,才有 50% 的概率遇到一次重复。

实际场景中的冲突风险 (伪随机性缺陷)#

虽然数学理论上几乎不可能重复,但实际应用中确实发生过冲突,原因通常在于:

  1. 随机源质量差:如果使用的编程语言或操作系统提供的伪随机数生成器(PRNG)种子不够随机(例如在容器启动初期熵池不足),可能会产生相同的 UUID。
  2. 状态重置:在 V1 中,如果系统时钟被大幅度回拨且时钟序列未持久化,可能会出现重复。

总结#

UUID 并非“绝对绝对”不重复,但在工程实践中,我们可以将其视为概率意义上的唯一

  • 追求唯一性与审计性:使用 V1(注意隐私)。
  • 追求匿名性与简单性:使用 V4。
  • 追求数据库性能与时间排序:强烈建议使用 V7
[programming] UUID 的实现逻辑
https://www.eustia-astraea.top/posts/programming/uuid-deep-dive/
作者
mcsl
发布于
2025-04-12
许可协议
CC BY-NC-SA 4.0