【问题标题】:UUID collision risk using different algorithms使用不同算法的 UUID 碰撞风险
【发布时间】:2011-03-03 13:18:45
【问题描述】:

我有一个数据库,其中 2 个(或者可能是 3 个或 4 个)不同的应用程序正在插入信息。新信息具有 GUID/UUID 类型的 ID,但每个应用程序都使用不同的算法来生成 ID。例如,一个使用 NHibernate 的“guid.comb”,另一个使用 SQLServer 的 NEWID(),另一个可能想要使用 .NET 的 Guid.NewGuid() 实现。

是否存在高于正常 ID 冲突或重复的风险?

谢谢!

【问题讨论】:

    标签: .net sql-server guid uuid


    【解决方案1】:

    是的,风险高于正常水平,因为所有这些都使用不同的“GUID”定义。 Guid.NewGuid() 是一个符合 RFC 的大部分随机 GUID,但 NEWSEQUENTIALID 是一个基于 MAC 地址和时间戳的重新排序(因此不符合 RFC)的 GUID,而 NHibernate 的梳形 GUID 完全不同(基于随机性和时间戳) )。

    您可能只想考虑对一种 GUID 实现进行标准化。我为我的所有应用程序使用我自己类型的精梳 GUID。 My blog 简要描述了所有这些类型的 GUID,以及我自己的设计决策。

    【讨论】:

      【解决方案2】:

      碰撞风险略有升高,但仍然微乎其微。考虑一下:

      • Comb 和 NEWID/NEWSEQUENTIALID 都包含精​​度低至几毫秒的时间戳。因此,除非您在同一时刻从所有这些不同的来源生成大量 ID,否则 ID 确实不可能发生冲突。

      • GUID中不是基于时间戳的部分可以认为是随机的;大多数 GUID 算法将这些数字基于 PRNG。因此,这 10 个字节左右发生冲突的可能性与您使用两个单独的随机数生成器并观察冲突的顺序相同。

        想一想 - PRNG 可以并且确实重复数字,因此即使它们使用稍微不同的算法,它们中的两个之间发生冲突的可能性也不会明显高于仅使用其中一个发生冲突的可能性。这有点像每周玩相同的彩票号码与每周随机选择一组 - 中奖几率完全相同。

      现在,请记住,当您使用像 Guid.Comb 这样的算法时,您只有 10 位唯一符,这相当于 1024 个单独的值。因此,如果您在相同的几毫秒内生成大量 GUID,您 发生冲突。但是,如果您以相当低的频率生成 GUID,那么您同时使用多少种不同的算法并不重要,冲突的可能性实际上仍然不存在。

      让您绝对确定的最佳方法是进行测试;让所有 2 或 3 个(或您使用的多个)同时生成 GUID,并定期将它们写入日志文件,并查看是否发生冲突(如果有,有多少)。这应该让您很好地了解这在实践中的安全性。

      附:如果您使用 NHibernate 的梳生成器为集群主键生成 GUID,请考虑使用 NEWSEQUENTIALID() 而不是 NEWID() - Comb 的全部目的是避免页面拆分,如果您有其他使用非顺序算法的过程。您还应该使用 Guid.NewGuid 更改任何代码以使用相同的 Comb 生成器 - NHibernate 中使用的实际 Comb 算法是 not complicated 并且很容易在您自己的域逻辑中复制。

      †​​ 请注意,关于NEWID 以及它是否包含时间戳似乎存在一些争议。在任何情况下,由于它基于 MAC 地址,因此可能值的范围比 V4 GUID 或 Comb 小得多。我建议坚持使用数据库外部的 Comb GUID 和数据库内部的 NEWSEQUENTIALID 的进一步原因。

      【讨论】:

      • 虽然我(大部分)同意你的结论,但我必须指出几个错误。 NEWID 不包含时间戳; NEWSEQUENTIALID 和 Comb 的时间戳存储在不同的字节中,因此您可以从不同时间生成的“GUID”中获取冲突。此外,使用时间戳(例如 NEWSEQUENTIALID)的 GUID 用 PRNG 编号填充其余部分;他们使用 MAC 地址。这就是为什么我建议对单一的 Guid 生成算法进行标准化。
      • @Stephen:我无法证明或反驳 NEWID 是基于时间戳的,因为文档很少,但 AFAIK 它基于使用时间戳的 GUID 算法的 V1。 Comb 和NEWSEQUENTIALID 的时间戳字节必须是相同的字节,否则它们实际上不会是连续的。 (它们使用不同大小的时间戳,是的,但较小的大小是 10 字节,因此对于低于 3.33 毫秒的插入频率,结果仍然是无冲突的)。
      • 无论如何,我已经添加了免责声明;不管NEWID() 实际如何生成它的ID,如果您打算在客户端使用Combs,最好在服务器上使用NEWSEQUENTIALID
      • NEWID 是一个 RFC4122 V4 GUID(完全随机,除了 6 位使其符合 RFC4122 标准)。 NEWSEQUENTIALID 是一个 V1 GUID,但它交换了许多字节以说明 SQL Server 对 GUID 的疯狂排序。虽然NEWSEQUENTIALID GUID 实际上是连续的,但梳状 GUID 通常不是。它们的时间戳不使用相同的字节; NEWSEQUENTIALID GUID 在它们的第一组中有时间戳,但 Comb GUID 将它放在最后一组。有关血腥细节,请参阅my blog post 中的链接。
      • “10 个字节的唯一符,相当于 1024 个单独的值”你的意思是位。
      猜你喜欢
      • 1970-01-01
      • 2013-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-05
      • 1970-01-01
      • 2015-03-31
      • 1970-01-01
      相关资源
      最近更新 更多