UUID真的是全球唯一吗?

0 阅读4分钟

刚刚在一个知乎回答看到几百万uuid就出现冲突,这根本不可能!

于是,我干脆跑一亿uuid试试。

具体来说,我做了一个持续运行的实验:​UUID 冲突实验室。

后端用 Java 的 UUID.randomUUID() 不停生成 UUIDv4,写进一张 MySQL 表,用主键做精确查重。

页面首屏就两个关键数字:表里现在有多少行,至今撞过几次。

写这篇文章时,行数已经超过 1 亿,冲突次数是 0。这两个数字还在变,以页面实时显示为准。

实验怎么搭的

表结构只有一列:

CREATE TABLE uuid_collision_seen (
    id BINARY(16) NOT NULL PRIMARY KEY
) ENGINE=InnoDB;

UUID 去掉连字符后是 16 字节,直接存二进制。写入用多行 INSERT IGNORE,每批 5000 条,4 批并发;撞上主键的行会被自动跳过,写入不会中断。

只数 INSERT IGNORE 跳过的差值不够严谨,所以每批插入前会先查一次本批里哪些 UUID 已经存在,把冲突事件写进独立的账本表,记录 UUID、首次时间、最近时间和累计次数。页面上的「冲突判定」读的就是账本。主表超过 1.01 亿会被裁剪回 1 亿,账本是独立表,历史冲突计数不受影响。

后台任务每 10 秒检查一次行数,不够 1 亿就继续补齐。这个实验就能一直在跑。

页面上还能亲手做两件事:

  • 粘贴任意一个 UUIDv4,走主键索引查它在不在这张一亿行的表里,返回是否命中和查询耗时;
  • 点按钮现场追加 1,000 / 10,000 / 100,000 条,看真实耗时、新插入数、重复数和写入速度。

实测结果

截至写稿:

  • 数据库实际行数:超过 100,000,000,原始 UUID 负载约 1.49 GiB
  • 账本记录的冲突次数:0

1 亿条 UUIDv4 放进去,零冲突。

为什么 1 亿条撞不上

UUID 一共 128 位。UUIDv4 固定了 4 位版本号和 2 位变体位,剩下 122 位由随机数填充,取值空间:

2^122 ≈ 5.316 × 10^36

冲突概率由生日问题决定,关键在样本两两配对的数量。1 亿条 UUID 能组成的配对数:

100000000 × 99999999 / 2 ≈ 5 × 10^15(约五千万亿对)

至少出现一次冲突的概率近似:

P ≈ 1 - e^(-5×10^15 / 5.316×10^36) ≈ 9.41 × 10^-22

想把冲突概率推到 50%,样本量要到约 2.71 × 10^18 条。换算成时间:每秒生成 10 亿条、昼夜不停跑大约 86 年,才有一次五成机会撞出一对。

回头看「几百万条就撞了」的说法。几百万条对应的冲突概率在 10^-24 量级,比上面的 10^-22 还要低两个数量级。这个量级的事件真实发生,概率解释已经不够用,更合理的排查方向是实现链路,这里就不展开说了。


所以,UUID 是全球唯一吗

严格回答这个问题:UUIDv4 的唯一性是概率性的,标准本身没有承诺绝对唯一。

RFC 9562 没有设立任何中心登记机构,任意两台机器各自生成,数学上存在产生相同值的通道。它的唯一性建立在两个条件上:随机空间足够大(122 位),实现遵守规范且随机源足够好。

两个条件都满足时,1 亿条、10 亿条规模下的冲突概率低到可以忽略,工程上把它当全球唯一标识来用,这个用法有数学背书。任何一个条件被破坏,比如随机源退化或者 ID 被截短,唯一性承诺随之失效,百万级撞车就不奇怪了。

正确实现的 UUIDv4 可以在工程上视为全球唯一。它提供的数学保证是概率性的,而这个概率到底有多低,我已经用一亿条真实数据放进 demo 里了。

数据就挂在那里,可以自己查

实验还在跑。​UUID 冲突实验室

首屏实时显示 MySQL 里的行数和冲突判定,你可以:

  • 看当前这一亿行的实测状态;
  • 把自己代码里生成的 UUIDv4 贴进去,查它有没有撞进这张表;
  • 亲手点一次「追加 100,000 条」,给这张表再添一份样本。

下次再看到「几百万条就撞 UUID」的说法,可以先对照这里的实测数字,再去检查对方的生成链路。


参考来源

  1. RFC 9562《Universally Unique IDentifiers (UUIDs)》:UUIDv4 的版本位、变体位与 122 个随机位定义,​https://datatracker.ietf.org/doc/html/rfc9562
  2. 生日问题近似公式:P ≈ 1 − e^(−n(n−1)/(2N))
  3. 本文实测数据来自 ​UUID 冲突实验室,页面实时刷新