java的UUID.randomUUID有多好?

我知道随机UUID在理论上有非常非常低的碰撞概率,但是我想知道在实践中,Java 5的randomUUID()在没有碰撞方面有多好? 有没有人分享经验?

UUID使用java.security.SecureRandom ,这应该是“密码强大的”。 虽然没有指定实际的实现,并且JVM之间可能有所不同(也就是说,所做的任何具体语句只对一个特定的JVM有效),但它确实要求输出必须通过统计随机数生成器testing。

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

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

为了使至less一次碰撞的概率为50%而需要生成的随机版本4UUID的数目是2.71,计算如下:

这个数字相当于在大约85年内每秒产生10亿个UUID,并且包含这么多UUID的文件(每个UUID 16个字节)将是大约45艾字节,比现有最大的数据库大很多倍数百PB的数量级。

因此,如果存在十亿分之一的重复机会,则必须生成103万亿个第4版UUID。

有没有人分享经验?

types4的UUID有2^122可能的值。 (规范说,你丢失了2位的types,另外4位的版本号。)

假设你每秒产生一百万个随机UUID,那么在你一生中重复出现的机会将会很小。 (为了检测重复,你必须解决每秒比较一百万个新的UUID与之前产生的所有UUID的问题 !)

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

当然,现在通常会使用伪随机数生成器,而不是真正的随机数。 但是我认为我们可以确信,如果你使用一个可信的提供者来获得你的密码强度随机数,那么这是密码强度,重复的概率将与理想的(非偏置的)随机数发生器。

但是,如果您使用带有“破损”密码随机数生成器的JVM,则所有投注都将closures。 (这可能包括某些系统中“熵不足”问题的一些解决方法,或者某人在您的系统或上游中对您的JRE进行修补的可能性。

我不是专家,但是我认为这些年来有足够聪明的人看着Java的随机数生成器。 因此,我也假定随机的UUID是好的。 所以你应该有理论上的碰撞概率(对所有可能的UUID来说大概是1: 3×10 ^ 38) ,有人知道这个随机UUID是如何变化的吗?是1/(16*4)吗?

从我的实际经验来看,迄今为止我从未见过任何碰撞。 当我拿到第一个的时候,我可能会长得惊人的长胡子;)

UUID的原始生成scheme是将UUID版本与生成UUID的计算机的MAC地址连接在一起,自西格里历日历通过以来,其数量为100纳秒。 通过表示空间(计算机)和时间(区间数)中的一个点,数值碰撞的机会实际上是零。

我去年玩彩票,我从来没有赢过……但似乎彩票有赢家…

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

types1:未实施。 如果在同一时刻生成uuid,则可能发生碰撞。 impl可以被人为地同步以绕过这个问题。

types2:从来没有看到一个实现。

types3:md5哈希:碰撞可能(128位-2技术字节)

types4:随机:碰撞可能(如彩票)。 请注意,jdk6 impl不使用“真正的”安全随机,因为PRNGalgorithm不是由开发人员select,你可以强制系统使用“穷人”的PRNGalgorithm。 所以你的UUID是可以预测的。

types5:sha1哈希:未实现:碰撞可能(160位-2技术字节)

在一个前雇主,我们有一个独特的列包含随机uuid。 我们在部署后的第一个星期就遇到了碰撞。 当然,可能性很低,但不是零。 这就是为什么Log4j 2包含UuidUtil.getTimeBasedUuid。 它将生成一个唯一的8,925年的UUID,只要在单个服务器上不会产生超过10,000个UUID /毫秒。

许多答案讨论了为了达到50%的碰撞几率必须产生多lessUUID。 但是碰撞必然(几乎)不可能的情况下,50%,25%甚至1%的碰撞概率对于应用程序毫无价值。

程序员是否经常将其视为“不可能”发生的其他事件?

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

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

这是一个天文数字,但是像国家医疗保健系统中的逐项计费,或者在大量设备上logging高频传感器数据等应用肯定会碰到这些限制。 如果您正在编写下一个银河系漫游指南,请勿尝试为每篇文章分配UUID!

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

我不是专家,但是因为每个人都在谈论理论,所以我想我可以通过举一个实际的例子给讨论添加一些东西。 在我的数据库中,我使用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-0ba00060fe64”

“be87a209-2114-45b3-9d5a-86d00060fe64”

“4a8a74a6-e972-4069-B480-bdea1177b21f”

“12fb4958-bee2-4c89-8cf8-edea1177b21f”

如果确实是随机的,那么拥有这种类似的UUID的概率就会相当低,因为我们只考虑了450万个条目。 所以,虽然这个function是好的,就没有碰撞而言,对我来说,理论上看起来不是那么好。

如果你真的想要确保没有碰撞,只需要添加自UUID-String前的历元开始的毫秒数。

 String id = System.currentTimeMillis() + "-" + UUID.randomUUID().toString(); 

所以为了每毫秒有50%的碰撞机会,你需要在一毫秒内创build2.71百万分之一,这是非常非常不可能的!

事实上,使用UUID的第一个数字还是比较安全的。 我已经testing了以下string的安全性:

 String id = UUID.randomUUID().toString().substring(0, 6); 

我已经testing过,我需要创build多less个这样的string才能碰撞。 创build约5163个string后,平均会发生碰撞! 为了产生碰撞,我需要创build的最less数量的string是53(我testing了它100000次)。 但是,如果我想用长度为8的string进行同样的testing,我甚至不能计算一次(我给了它20分钟的时间)。