【问题标题】:How good is Java's UUID.randomUUID?Java 的 UUID.randomUUID 有多好?
【发布时间】:2011-01-31 14:20:30
【问题描述】:

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

【问题讨论】:

  • 根据我的经验,我从未见过碰撞 ;-)
  • 算法在RFC1422中指定:ietf.org/rfc/rfc4122.txt
  • @skaffman:RFC 完全没有提到用于生成随机数字的算法。
  • 由于这是一个更开放的问题,我想我不会将任何答案标记为正确答案;相反,我会给我认为好的每个答案投一票:)
  • 来自维基百科:...换句话说,只有在接下来的 100 年每秒生成 10 亿个 UUID 之后,仅创建一个副本的概率约为 50%。

标签: java uuid


【解决方案1】:

我不是专家,但我认为多年来有足够多的聪明人关注 Java 的随机数生成器。因此,我还假设随机 UUID 是好的。所以你真的应该有理论上的碰撞概率(对于所有可能的 UUID,大约为 1:3 × 10^38。有人知道这仅对随机 UUID 有何变化吗?是上面的1/(16*4) 吗?)

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

【讨论】:

  • 来自维基百科:...换句话说,只有在接下来的 100 年每秒生成 10 亿个 UUID 之后,仅创建一个副本的概率约为 50%。
  • 实际上维基百科说它是未来 85 年......我说不要指望它,某个地方有人生成了与你相同的 UUID
【解决方案2】:

有人有经验分享吗?

类型 4 UUID 有 2^122 可能的值。 (规范说您会丢失 2 位的类型,以及另外 4 位的版本号。)

假设您每秒生成 100 万个随机 UUID,那么在您的一生中发生重复的可能性将微乎其微。为了检测重复,您必须解决每秒将 100 万个新 UUID 与 您之前生成的所有 UUID 进行比较的问题1

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

当然,您通常会使用伪随机数生成器,而不是真正随机数的来源。但我认为我们可以确信,如果您为您的加密强度随机数使用可靠的提供商,那么它是加密强度,并且重复的概率将与理想(无偏)随机数生成器。

但是,如果您要使用带有“损坏的”加密随机数生成器的 JVM,那么所有的赌注都将失败。 (这可能包括某些系统上“熵不足”问题的一些变通方法。或者有人在您的系统或上游修改了您的 JRE。)


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

【讨论】:

  • "(要检测重复项,您必须解决每秒将 100 万个新 UUID 与您之前生成的所有 UUID 进行比较的问题!)" - 这部分相对简单假设您已将 uuid 存储在某种二叉树结构中,则每个新 uuid 只需一个树下降。您无需将其与之前生成的所有 uuid 进行实际比较。
  • “在你的一生中发生重复的机会将微乎其微”,后代会谴责我们什么......
  • 也许他们会谴责我们假设每秒生成 10^6 个唯一 ID 是不现实的。或 10^12。或者可能没有意识到没有随机数这样的东西。或者其他难以想象的东西。但是......嘿......人们一直在对他们的祖先做出判断,它并没有改变任何东西。
【解决方案3】:

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

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

【讨论】:

  • “实现总是有可能包含细微的错误......” - 或者(戴上锡箔帽)......故意的细微缺陷。 <:->
  • 加密强度与冲突问题完全无关。
  • @osa:不产生冲突(超出完全随机性的预期)几乎是 RNG 的最低质量要求,而加密强度是最高的。换句话说,一个加密强的 RNG绝对不会产生比预期更多的冲突。
  • 不过,请注意,如果您例如运行一个 JVM 在blogs.vmware.com/cto/… 中生成 UUID,你可能会遇到很多很多的冲突。所有的软件 RNG 都是 PRNG,它们最终只与它们的熵源一样好;两个种子相同的 PRNG 也会表现出相同的行为,而且在一致的、完全重复的服务器设置和启动过程中,这种情况经常会发生。
  • @user508633:我实际上希望在这种特定情况下获得 100% 的冲突率,但它确实是一个非常具体的情况,远远超出了“一致、完全重复的服务器设置和启动过程” .我敢肯定,如果你只是克隆一个虚拟机并正常运行它,你不会得到任何增加的冲突率。 SecureRandom 的自我播种非常努力地获得一些真正的熵,如果找不到,就会阻塞执行:seancassidy.me/wiggle-the-mouse-to-fix-the-test.html
【解决方案4】:

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

为了有 50% 的概率至少发生一次冲突,需要生成的随机版本 4 UUID 的数量为 2.71 quintillion,计算如下:

...

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

...

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

【讨论】:

  • 我还引用了该页面,“如果地球上每个人都拥有 6 亿个 UUID,那么重复的概率大约为 50%。”
  • 这仅适用于真正的随机性,不适用于 javas UUID 之类的伪随机数。
  • @Markus:完全错误。良好的伪随机 RNG(尤其是加密性强的 RNG)的冲突概率与“真正的”随机性没有什么不同。
  • @Eric - 我认为你有责任支持你的断言。 FWIW,我能想到的唯一一种情况是 4 类 UUID 会更频繁地发生碰撞,而概率论认为它们应该是:1) 加密随机数的错误来源,或 2) UUID 库已被泄露。
  • 这不能回答所提出的问题。问题是关于 Java 的 UUID.randomUUID() 中随机性的质量,而不是关于给定完美随机数生成器的理论机会。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    我去年玩彩票,但我从来没有赢过.... 但似乎有彩票有中奖者......

    文档:https://www.rfc-editor.org/rfc/rfc4122

    类型 1:未实现。如果同时生成 uuid,则可能发生冲突。 impl 可以人为地进行异步同步以绕过这个问题。

    类型 2:永远看不到实现。

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

    类型 4:随机:可能发生碰撞(如彩票)。请注意,jdk6 impl 不使用“真正的”安全随机,因为 PRNG 算法不是由开发人员选择的,您可以强制系统使用“差”的 PRNG 算法。所以你的 UUID 是可预测的。

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

    【讨论】:

    • 彩票中奖的概率可能是十分之一或一亿分之一(10^7 或 10^8)或类似的数值。与 128 位随机数发生冲突的概率为 3.4 * 10^28。随时给我一张彩票!
    【解决方案7】:

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

    【讨论】:

    • 这个解释让我很乐观,不会在实践中看到碰撞。您能否指出该声明的任何参考(一些源代码会更好)?
    • 在规范ietf.org/rfc/rfc4122.txt 中找到了这个。不过很高兴看到实施。
    • 然而,该方案不是 Java 实现的。 Java 实现了 4 类 UUID,它是纯随机的,不包括 MAC 地址或时间。顺便说一句,由于现在有很多物理和虚拟设备可供您选择 MAC 地址,因此原始算法并不能保证唯一性。
    【解决方案8】:

    由于大多数答案都集中在理论上,我认为我可以通过进行实际测试来为讨论添加一些内容。在我的数据库中,我使用 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 万个条目。所以,虽然这个功能很好,但就没有碰撞而言,对我来说它似乎没有理论上的那么好。

    编辑

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

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

    这个 wiki 文章 en.wikipedia.org/wiki/Birthday_problem 中解释了公式

    【讨论】:

    • 这不是真的。即使在 4.5M uuid 上使用真正的随机数生成器,也会出现这种相似性。您提供的 UUID 之间的相似性很小而且相差甚远,哦,离完全碰撞还差得远。
    • 我完全同意你的看法,相似之处是“小”,远非完全冲突。但是,我只是想将 Java 的 UUID.randomUUID() 与真正的随机数生成器进行比较(这是问题)。通过一些计算我们可以看到,在一个真正的随机数生成器中,最后一种情况发生的概率大约是 1-e^(-4500000^2/(2*36^11)) = 0.007% = 1 13k。我必须非常幸运:)
    • 如果有 450 万件物品和 1.3 万分之一的机会,那么像这样的部分碰撞不会预期 346 次吗?
    • 您的期望是什么?相似不一样,不是吗?
    • 您匹配了 11 个十六进制位,16^11 或 2^44。这给出了在 450 万次试验中发生碰撞的概率为 62.5%。 1 - e^(-2^44.2/2^45)
    【解决方案9】:

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

    【讨论】:

    • 是的。但问题是询问随机(即类型 4)UUID。
    • 询问发生碰撞的可能性。言下之意是他想确保避免它们。
    • (碰撞很可能是由于 PRNG 播种的随机性来源损坏。我想我猜这可能是纯粹的偶然性。)
    【解决方案10】:

    许多答案都讨论了必须生成多少个 UUID 才能达到 50% 的碰撞几率。但是对于必须(实际上)不可能发生碰撞的应用程序来说,50%、25% 甚至 1% 的碰撞几率是毫无价值的。

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

    当我们将数据写入磁盘或内存并再次读回时,我们理所当然地认为数据是正确的。我们依靠设备的纠错来检测任何损坏。但未检测到错误的几率实际上在 2-50 左右。

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

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

    【讨论】:

    • 作为一个比较点,赢得强力球头奖的机会是 3 亿分之一,但通常销售 10 到 2000 万张彩票。关键是,许多人将“不可能”定义为少于亿分之一的机会。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 1970-01-01
    • 1970-01-01
    • 2011-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多