我知道理论上随机UUID发生冲突的可能性非常非常非常低,但是我想知道实际上Java randomUUID()
在没有冲突方面有多好?有没有人可以分享经验?
我知道理论上随机UUID发生冲突的可能性非常非常非常低,但是我想知道实际上Java randomUUID()
在没有冲突方面有多好?有没有人可以分享经验?
Answers:
UUID使用java.security.SecureRandom
,应该被认为是“加密强”的。虽然未指定实际的实现,并且在JVM之间可能有所不同(这意味着所做的任何具体语句仅对一个特定的JVM有效),但它确实要求输出必须通过统计随机数生成器测试。
一个实现总是有可能包含破坏所有这些的细微错误(请参阅OpenSSH密钥生成错误),但我认为没有任何具体的理由担心Java UUID的随机性。
维基百科有一个很好的答案 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。
UUID.randomUUID()
,而不是给定完美随机数生成器的理论机会。
有没有人可以分享经验?
有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的碰撞所需的时间长度,我认为这不可行。甚至没有(假设的)聪明的表述。
我不是专家,但是我认为多年来有足够的聪明人看过Java的随机数生成器。因此,我还要假设随机UUID是好的。因此,您应该真正具有理论上的碰撞概率(所有可能的UUID的碰撞概率约为1:3×10 ^ 38。有人知道这仅对随机UUID产生怎样的变化吗?是否是1/(16*4)
以上所述?)
根据我的实际经验,到目前为止,我从未见过任何碰撞。我拿到第一个胡子的那一天,我可能会留出惊人的长胡子;)
UUID的原始生成方案是将UUID版本与生成UUID的计算机的MAC地址,以及自西方采用格里高利历以来的100纳秒间隔连接起来。通过表示空间(计算机)和时间(间隔数)中的单个点,值发生冲突的机会实际上为零。
许多答案都讨论了要生成50%的碰撞机会,必须生成多少个UUID。但是,对于必须(实际上)不可能发生碰撞的应用程序,发生碰撞的机会有50%,25%甚至1%毫无价值。
程序员是否会例行地将可能发生并确实发生的其他事件视为“不可能”?
当我们将数据写入磁盘或内存并再次读回时,我们认为数据是正确的。我们依靠设备的错误纠正来检测任何损坏。但是,未被发现的错误的可能性实际上是2 -50左右。
将类似的标准应用于随机UUID是否有意义?如果这样做,您会发现在大约1000亿个随机UUID(2 36.5)的集合中可能发生“不可能”的冲突。
这是一个天文数字,但是诸如国家医疗保健系统中的逐项计费或在大量设备上记录高频传感器数据之类的应用肯定可以突破这些限制。如果要编写下一本《银河旅行者指南》,请不要尝试为每篇文章分配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-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中解释了公式
我去年参加彩票活动,但我从未赢过钱....但看来那里的彩票有赢家...
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技术字节)