我知道随机uuid在理论上有非常非常非常低的碰撞概率,但我想知道,在实践中,Java的randomUUID()在没有碰撞方面有多好?有人有经验可以分享吗?
我不是专家,但我认为已经有足够多的聪明人研究过Java的随机数生成器。因此,我还假定随机uuid是好的。所以你应该有理论上的碰撞概率(对于所有可能的uuid,碰撞概率约为1:3 × 10^38)。有人知道这只对随机uuid有什么变化吗?是上面的1/(16*4)吗?)
从我的实际经验来看,到目前为止我还从未见过任何碰撞。我第一次留胡子的那天可能已经长出了惊人的长胡子;)
有人有经验可以分享吗?
type-4 UUID有2^122个可能的值。(规范说,类型损失2位,版本号损失4位。)
假设您每秒生成100万个随机uuid,那么在您的一生中出现重复uuid的几率将微乎其微。为了检测重复,您必须解决每秒将100万个新uuid与之前生成的所有uuid进行比较的问题1!
任何人在现实生活中经历(即实际注意到)一个复制品的机会甚至比消失的小得多……因为寻找碰撞的实际困难。
当然,您通常会使用伪随机数生成器,而不是真正的随机数源。但我认为我们可以确信,如果您使用可信的提供商来提供加密强度随机数,那么它将是加密强度,并且重复的概率将与理想(无偏差)随机数生成器相同。
然而,如果你要使用一个带有“坏掉的”加密随机数生成器的JVM,那么一切都是徒劳的。(这可能包括一些系统上“熵不足”问题的变通方法。或者有人在您的系统或上游对您的JRE进行了修补。)
1 - Assuming that you used "some kind of binary btree" as proposed by an anonymous commenter, each UUID is going to need O(NlogN) bits of RAM memory to represent N distinct UUIDs assuming low density and random distribution of the bits. Now multiply that by 1,000,000 and the number of seconds that you are going to run the experiment for. I don't think that is practical for the length of time needed to test for collisions of a high quality RNG. Not even with (hypothetical) clever representations.
UUID使用java.security。SecureRandom,它被认为是“加密强的”。虽然没有指定实际的实现,并且在不同的JVM之间可能有所不同(这意味着所做的任何具体语句只对一个特定的JVM有效),但它确实要求输出必须通过统计随机数生成器测试。
实现中总是可能包含破坏这一切的细微错误(参见OpenSSH密钥生成错误),但我不认为有任何具体理由担心Java uuid的随机性。
维基百科给出了一个很好的答案 http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions
the number of random version 4 UUIDs which need to be generated in order to have a 50% probability of at least one collision is 2.71 quintillion, computed as follows: ... This number is equivalent to generating 1 billion UUIDs per second for about 85 years, and a file containing this many UUIDs, at 16 bytes per UUID, would be about 45 exabytes, many times larger than the largest databases currently in existence, which are on the order of hundreds of petabytes. ... Thus, for there to be a one in a billion chance of duplication, 103 trillion version 4 UUIDs must be generated.
我去年买彩票,但我从来没有中过.... 但似乎彩票中了奖…
Doc: https://www.rfc-editor.org/rfc/rfc4122
类型1:未实现。如果uuid在同一时刻生成,则可能发生冲突。Impl可以人为地实现a同步,以绕过这个问题。
类型2:从未看到实现。
类型3:md5哈希:可能发生冲突(128位-2技术字节)
类型4:随机:可能发生碰撞(如抽签)。注意jdk6 impl没有使用一个“真正的”安全随机,因为PRNG算法不是由开发人员选择的,你可以强制系统使用一个“糟糕的”PRNG算法。所以UUID是可预测的。
类型5:sha1哈希:未实现:可能发生冲突(160位-2技术字节)
UUID的原始生成方案是将UUID版本与生成UUID的计算机的MAC地址以及自西方采用格里高利历法以来的100纳秒间隔数连接起来。通过表示空间(计算机)和时间(间隔数)中的单个点,值碰撞的机会实际上为零。
在以前的雇主那里,我们有一个包含随机uuid的唯一列。在部署后的第一周就发生了碰撞。当然,几率很低,但也不是零。这就是为什么Log4j 2包含UuidUtil.getTimeBasedUuid。只要在一台服务器上每毫秒生成的UUID不超过10,000个,它就会生成一个在8,925年内惟一的UUID。
许多答案都讨论了需要生成多少uuid才能达到50%的碰撞几率。但是50%、25%甚至1%的碰撞概率对于一个必须(实际上)不可能发生碰撞的应用程序来说是毫无价值的。
程序员是否经常将其他可能发生的事件视为“不可能”?
当我们将数据写入磁盘或内存并再次读取时,我们想当然地认为数据是正确的。我们依靠设备的纠错功能来检测任何损坏。但是,未检测到错误的几率实际上在2-50左右。
对随机uuid应用类似的标准不是很有意义吗?如果您这样做,您将发现在大约1000亿个随机uuid(236.5)的集合中,“不可能”的碰撞是可能的。
这是一个天文数字,但像国家医疗保健系统中的逐项计费,或在大量设备上记录高频传感器数据等应用程序肯定会遇到这些限制。如果你正在写下一篇《银河系漫游指南》,不要试图为每篇文章分配uuid !
推荐文章
- 转换列表的最佳方法:map还是foreach?
- 如何分割逗号分隔的字符串?
- Java字符串—查看字符串是否只包含数字而不包含字母
- Mockito.any()传递带有泛型的接口
- 在IntelliJ 10.5中运行测试时,出现“NoSuchMethodError: org.hamcrest. matcher . descripbemismatch”
- 使用String.split()和多个分隔符
- Java数组有最大大小吗?
- 在Android中将字符串转换为Uri
- 从JSON生成Java类?
- 为什么java.util.Set没有get(int index)?
- Swing和AWT的区别是什么?
- 为什么Java流是一次性的?
- 四舍五入BigDecimal *总是*有两位小数点后
- 设计模式:工厂vs工厂方法vs抽象工厂
- Java:检查enum是否包含给定的字符串?