Java的UUID.randomUUID有多好?


311

我知道理论上随机UUID发生冲突的可能性非常非常非常低,但是我想知道实际上Java randomUUID()在没有冲突方面有多好?有没有人可以分享经验?


10
根据我的经验,我从未见过碰撞;-)
Thilo

4
算法在RFC1422中指定: ietf.org/rfc/rfc4122.txt
skaffman 2010年

8
@skaffman:RFC完全没有提及用于生成随机数字的算法。
Michael Borgwardt 2010年

4
由于这是一个开放式的问题,我想我不会将任何答案标记为正确答案。相反,我将对我认为不错的每个答案都投一票:)
艾尔文(Alvin)2010年

5
摘自维基百科:...换句话说,只有在接下来的100年中每秒生成10亿个UUID之后,才创建一个副本的可能性约为50%。
MaVRoSCy 2012年

Answers:


168

UUID使用java.security.SecureRandom,应该被认为是“加密强”的。虽然未指定实际的实现,并且在JVM之间可能有所不同(这意味着所做的任何具体语句仅对一个特定的JVM有效),但它确实要求输出必须通过统计随机数生成器测试。

一个实现总是有可能包含破坏所有这些的细微错误(请参阅OpenSSH密钥生成错误),但我认为没有任何具体的理由担心Java UUID的随机性。


34
“实现总是可能包含细微的错误……” -或(戴上锡纸帽子)……故意的细微缺陷。<:-)
Stephen C

25
密码强度与冲突问题完全无关。
osa 2015年

14
@osa:不产生冲突(超出完全随机性的预期范围)几乎是RNG的最低质量要求,而加密强度最高。换句话说,具有加密功能的RNG 绝对不会产生比预期更多的冲突。
Michael Borgwardt 2015年

3
但是,可能有必要指出,例如,如果运行一个JVM,在blogs.vmware.com/cto/…中搅动UUID ,则可能会发生很多冲突。所有的软件RNG都是PRNG,最终它们的熵只有它的来源。两个相同种子的PRNG也将表现相同,并且在一致,精确重复的服务器设置和启动过程中,经常会发生意外。
user508633

@ user508633:在这种情况下,我实际上希望获得100%的冲突率,但实际上,这是一个非常具体的情况,远远超出了“一致,精确重复的服务器设置和启动过程”。我很确定,如果您仅克隆一个VM并正常运行它,则不会增加任何冲突率。SecureRandom的自我植入非常努力地获取一些真实的熵,以至于如果找不到它,就会阻止执行:seancassidy.me/wiggle-the-mouse-to-fix-the-test.html
Michael Borgwardt 2015年

114

维基百科有一个很好的答案 http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions

为了产生至少一次碰撞的50%概率而需要生成的随机版本4 UUID的数量为2.71亿五千万,计算如下:

...

此数字等效于在大约85年的时间里每秒生成10亿个UUID,而包含这么多UUID(每个UUID为16个字节)的文件大约为45艾字节,比目前存在的最大数据库大很多倍。数百PB的数量级。

...

因此,要有十亿分之一的重复机会,必须生成103万亿个版本4 UUID。


56
我还要从该页面引用:“如果地球上每个人都拥有6亿个UUID,则重复一次的概率约为50%。”
杰夫·阿克塞尔罗德

24
这仅适用于真正的随机性,不适用于javas UUID之类的伪随机数。
Markus

9
@Markus:完全错误。良好的伪随机RNG(尤其是加密强RNG)发生碰撞的可能性与“真实”随机性没有区别。
Michael Borgwardt

6
@Eric-我认为您有责任支持自己的主张。FWIW,我能想到的唯一场景是4型UUID在哪里发生冲突的可能性更大,概率论认为它们应该是:1)加密随机数的不良来源,或者2)遭到破坏的UUID库。
Stephen C

13
这不能回答所问的问题。问题是关于Java语言中随机性的质量UUID.randomUUID(),而不是给定完美随机数生成器的理论机会。
kratenko 2014年

69

有没有人可以分享经验?

2^122用于4型UUID可能的值。(规范说,该类型丢失2位,版本号丢失4位。)

假设您每秒要生成一百万个随机UUID,那么在您的一生中发生重复的可能性将很小。并检测重复的,你必须要解决比较每秒1万点新的UUID对问题的所有以前生成的UUID的1

由于寻找碰撞的实际困难,任何人在现实生活中经历(即实际上注意到)重复的机会甚至比消失的机会要小。

当然,现在,您通常将使用伪随机数生成器,而不是真正的随机数源。但我认为,我们可以相信,如果你正在使用你的加密强度随机数的可信供应商,那么它就会被加密强度,并重复的概率是相同的理想(不带偏见的)随机数发生器。

但是,如果您将JVM与“中断的”加密随机数生成器一起使用,则所有选择都不可用。(这可能包括某些系统上的“熵不足”问题的一些解决方法。或者在系统上或上游有人修补了您的JRE的可能性。)


1-假设您使用了匿名评论者建议的“某种二进制btree”,则每个UUID将需要O(NlogN)RAM内存中的位来表示N不同的UUID,并假设这些位的密度低且分布随机。现在,将其乘以1,000,000以及您要运行实验的秒数。对于测试高质量RNG的碰撞所需的时间长度,我认为这不可行。甚至没有(假设的)聪明的表述。


4
“(并且要检测重复项,您必须解决将每秒一百万个新UUID与先前生成的所有UUID进行比较的问题!)”-假设您已将uuid存储在某些位置,则该部分相对简单一种二叉树结构,每个新的uuid只是一个树后裔。您实际上不需要将其与所有先前生成的uuid分别进行实际比较。
user467257

20

我不是专家,但是我认为多年来有足够的聪明人看过Java的随机数生成器。因此,我还要假设随机UUID是好的。因此,您应该真正具有理论上的碰撞概率(所有可能的UUID的碰撞概率约为1:3×10 ^ 38。有人知道这仅对随机UUID产生怎样的变化吗?是否是1/(16*4)以上所述?)

根据我的实际经验,到目前为止,我从未见过任何碰撞。我拿到第一个胡子的那一天,我可能会留出惊人的长胡子;)


10
摘自维基百科:...换句话说,只有在接下来的100年中每秒生成10亿个UUID之后,才创建一个副本的可能性约为50%。
MaVRoSCy 2012年

1
实际上,维基百科说这是未来的85年。。。我说不要指望它,某处某
人生成了

12

在前雇主那里,我们有一个独特的栏,其中包含一个随机的uuid。部署后的第一周,我们发生了一次碰撞。当然,赔率很低,但不为零。这就是Log4j 2包含UuidUtil.getTimeBasedUuid的原因。只要您在单个服务器上生成的UUID不超过10,000 U / ID /毫秒,它将生成8925年唯一的UUID。


2
是。但是问题是询问随机(即4型)UUID。
斯蒂芬·C

1
它正在询问发生碰撞的可能性。言外之意是他想确保避免他们。
rgoers

1
(碰撞很可能是由于PRNG植入的随机性中断了。我想这可能是由于纯属偶然。)
Stephen C

9

UUID的原始生成方案是将UUID版本与生成UUID的计算机的MAC地址,以及自西方采用格里高利历以来的100纳秒间隔连接起来。通过表示空间(计算机)和时间(间隔数)中的单个点,值发生冲突的机会实际上为零。


1
这种解释使我很乐观,不会在实践中看到冲突。您能否指向该语句的任何参考(某些源代码会更好)?
DraganMarjanović18年

在规范ietf.org/rfc/rfc4122.txt中找到了此文件。尽管如此,看到执行情况还是很棒的。
DraganMarjanović18年

1
但是,该方案不是Java实现的。Java实现类型4 UUID,它是纯随机的,并且不包括MAC地址或时间。顺便说一句,由于现在有很多物理和虚拟设备可以选择MAC地址,因此原始算法不能保证唯一性。
索伦Boisen

8

许多答案都讨论了要生成50%的碰撞机会,必须生成多少个UUID。但是,对于必须(实际上)不可能发生碰撞的应用程序,发生碰撞的机会有50%,25%甚至1%毫无价值。

程序员是否会例行地将可能发生并确实发生的其他事件视为“不可能”?

当我们将数据写入磁盘或内存并再次读回时,我们认为数据是正确的。我们依靠设备的错误纠正来检测任何损坏。但是,未被发现的错误的可能性实际上是2 -50左右。

将类似的标准应用于随机UUID是否有意义?如果这样做,您会发现在大约1000亿个随机UUID(2 36.5)的集合中可能发生“不可能”的冲突。

这是一个天文数字,但是诸如国家医疗保健系统中的逐项计费或在大量设备上记录高频传感器数据之类的应用肯定可以突破这些限制。如果要编写下一本《银河旅行者指南》,请不要尝试为每篇文章分配UUID!


相比之下,赢得强力球大奖的机会是3亿分之一,但是通常售出10到2000万张彩票。关键是,许多人将“不可能”定义为几亿个机会中少于一个的机会。
erickson

4

因为大多数答案都集中在理论上,所以我认为我可以通过给出我的实际测试来为讨论添加些东西。在我的数据库中,使用Java 8 UUID.randomUUID()生成了大约450万个UUID。以下是我发现的一些内容:

c0f55f62 -b990-47bc-8caa-f42313669948

c0f55f62 -e81e-4253-8299-00b4322829d5

c0f55f62 -4979-4e87-8cd9-1c556894e2bb


b9ea2498-fb32-40ef-91ef-0ba 00060fe64

be87a209-2114-45b3-9d5a-86d 00060fe64


4a8a74a6-e972-4069-b480-b dea1177b21f

12fb4958-bee2-4c89-8cf8-e dea1177b21f

如果它确实是随机的,那么拥有此类相似的UUID的可能性将会非常低(请参阅编辑),因为我们仅考虑了450万个条目。因此,尽管此功能不错,但就没有碰撞而言,对我而言,它似乎并不像理论上的那么好。

编辑

很多人似乎不理解这个答案,所以我要澄清我的观点:我知道相似之处很小,而且还没有完全冲突。但是,我只是想将Java的UUID.randomUUID()与真正的随机数生成器进行比较,这才是真正的问题。

在真正的随机数生成器中,最后一种情况发生的概率约为0.007%。因此,我认为我的结论是正确的。

此Wiki文章en.wikipedia.org/wiki/Birthday_problem中解释了公式


6
这不是真的。即使在4.5M uuid上使用真正的随机数生成器,也会出现此类相似性。您提供的UUID之间的相似性很小而且相距甚远,距离完全碰撞还很遥远。
user3711864

我完全同意您的观点,即相似性很小,相距甚远。但是,我只想将Java的UUID.randomUUID()与真正的随机数生成器进行比较(这是问题所在)。通过一些计算,我们可以看到,在一个真正的随机数生成器中,最后一个情况发生的概率约为1-e ^(-4500000 ^ 2 /(2 * 36 ^ 11))= 0.007%= 1 13k。我本来是很幸运:)
安德烈·皮涅罗

1
随着450万分的项目和13K机会1,不会像部分碰撞会预计 346次?
李本

不,@ BenLee,我考虑到我们有450万个商品,因此计算出发生该事件的可能性。每个项目发生的几率都不是1k的三分之一。我使用的公式可以在此Wiki文章中找到 en.wikipedia.org/wiki/Birthday_problem
安德烈·皮涅罗

2
您的期望是什么?相似是不一样的,不是吗?
Koray Tugay

3

我去年参加彩票活动,但我从未赢过钱....但看来那里的彩票有赢家...

doc:http//tools.ietf.org/html/rfc4122

类型1:未实现。如果uuid是在同一时刻生成的,则可能发生碰撞。impl可以人为地进行a同步以绕过此问题。

类型2:从不看实现。

类型3:md5哈希:可能发生冲突(128位2技术字节)

类型4:随机:可能发生碰撞(与彩票一样)。请注意,jdk6不使用“ true”安全随机数,因为开发人员未选择PRNG算法,并且您可以强制系统使用“不良” PRNG算法。因此,您的UUID是可预测的。

类型5:sha1哈希:未实现:可能发生冲突(160 bit-2技术字节)


4
赢得彩票的概率可能是十分之一或一亿(10 ^ 7或10 ^ 8)之类。与128位随机数发生冲突的概率为3.4 * 10 ^ 28。随时给我一张彩票!
史蒂芬·C

0

我们已经在应用程序中使用Java的随机UUID一年多了,而且已经非常广泛了。但是我们从来没有碰到过碰撞。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.