使用哪个UUID版本?

467

你应该使用哪个版本的UUID?我看到了很多线程解释每个版本包含的内容,但我很难确定什么适用于什么应用程序。


2
你有哪些选择? - Gabe
任何与Python兼容的内容。所以我猜这个http://docs.python.org/2/library/uuid.html。1,3,4,5。 - user1802143
如果您对版本3和5感到好奇,请参阅此问题,生成v5 UUID。名称和命名空间是什么? - Basil Bourque
6个回答

588

生成UUID有两种不同的方法。

如果您只需要一个唯一的ID,您需要版本1或版本4。

  • 版本1:这将基于网络卡MAC地址和当前时间生成一个唯一ID。如果其中任何一项在任何方面都是敏感的,请勿使用此选项。该版本的优点在于,当查看由您信任的机器生成的UUID列表时,您可以轻松地知道许多UUID是否由同一台机器生成,或者推断它们之间的时间关系。

  • 版本4:这些是从随机(或伪随机)数字生成的。如果您只需生成UUID,则可能需要使用此选项。该版本的优点在于,在调试并查看与UUID匹配的大量信息时,更容易快速发现匹配项。

如果您需要根据给定名称生成可重复UUID,则需要版本3或版本5。如果您正在与其他系统交互,则已经做出了此选择,您应该检查他们使用哪个版本和命名空间。

  • 版本3:这将从命名空间和名称的MD5哈希中生成唯一ID。如果您正在处理非常严格的资源要求(例如非常繁忙的Arduino板),请使用此选项。

  • 版本5:这将从命名空间和名称的SHA-1哈希中生成唯一ID。这是更安全且通常推荐的版本。


32
我想补充一点: 如果您需要从给定的名称生成一个可重现的UUID,您需要使用版本3或版本5。 如果您将相同的输入提供给该算法,它将生成相同的输出。 - anregen
4
在云计算环境中(例如AWS或GAE),版本1的弱点似乎已经被彻底减轻。随着时间推移,可能会应用于给定应用程序UUID生成器的数千个不同的MAC地址,从而消除了可预测性和/或可追溯性。 - Buffalo Rabor
8
关于版本1“不推荐”的评论,过于简单化。在许多情况下,这些确实是可以接受和优选的。但是,如果你对从UUID泄露以下信息中的任何一个感到安全上的担忧并且可能暴露给不可信的人员:(a)创建UUID的机器的MAC地址,或者(b)创建时的日期时间,则应避免使用版本1。如果这两个信息不敏感,则版本1是一个很好的选择。 - Basil Bourque
32
第2版发生了什么事? - Matthew Woo
5
如果想要0(不是无限小,而是真正的0)碰撞概率,版本1 UUID是完全合适的。但是,根据RFC4122的规定,UUID不应用于安全目的:https://tools.ietf.org/html/rfc4122#section-6 - Deimos
显示剩余7条评论

66
如果您需要一个随机数,请使用随机数库。如果您需要一个几乎没有碰撞可能性的唯一标识符,应该使用UUIDv1。请参见Nick的帖子以了解UUIDv3和v5。
UUIDv1并不安全。它并不是为了安全而设计的,而是为了唯一性。UUIDv1使用当前时间戳、机器标识符和一些类似随机的东西生成一个数字,这个算法再也不会生成相同的数字。这对于交易ID很合适(即使每秒进行数百万次交易)。

说实话,我不明白为什么UUIDv4存在...从阅读RFC4122来看,这个版本并没有消除碰撞的可能性。它只是一个随机数生成器。如果这是真的,那么世界上有两台机器最终创建相同的"UUID"v4(引号因为没有保证通用唯一性的机制),这种情况下,我认为该算法不应该出现在描述生成唯一值方法的RFC中,而应该出现在描述生成随机性的RFC中。对于一组随机数:

chance_of_collision = 1 - (set_size! / (set_size - tries)!) / (set_size ^ tries)

92
除非您在一个世纪内每秒生成十亿个UUID并赢得一个硬币翻转,否则不会出现两个UUID版本4实现的冲突。请记住,“set_size”是2^122,非常大。 - Kevin
16
V4算法不是串行的,这意味着v4生成的前两个UUID有可能匹配。仅仅因为选项很多,并不意味着在用完所有独特的选项之前就会重复。这种情况可能随时发生。 - anregen
10
你未能真正计算。我们(作为一个物种)不会每秒生成10亿个UUID。因此,平均而言,我们比100年更长时间才会发生第一次碰撞。 - Kevin
51
V4 "可能会"发生碰撞,但对于大多数用例来说,这种概率异常低,不值得冒险。关于“世界上可能最终创建相同的'UUID'v4的两台机器”,当然存在这样的情况,但这并不是问题,因为大多数使用UUID的机器会在不同的上下文中使用它们。我的意思是,如果我为自己的内部应用程序生成与你为你的内部应用程序生成的相同的UUID,那就无所谓了。只有在发生在相同上下文中时,碰撞才有影响。(请记住,即使在应用程序内部,许多UUID不必在整个应用程序中唯一,只需在它们使用的上下文中唯一即可)。 - user21037
10
听起来,如果你不需要你的 GUID 是安全的,就使用版本 1。如果你需要它是安全的,并且感觉幸运(或者真的不感到不幸),那么使用版本 4。 - Vaccano
显示剩余7条评论

22

这是一个非常普遍的问题。一个答案是:“这取决于您想要生成什么类型的UUID”。但更好的答案是:“在回答之前,能告诉我们为什么您需要编码自己的UUID生成算法而不是调用大多数现代操作系统提供的UUID生成功能吗?”

这样做更容易、更安全,而且由于您可能不需要生成自己的UUID,那么何必费力实现呢?在这种情况下,答案就是使用您的操作系统、编程语言或框架提供的功能。例如,在Windows中,有CoCreateGuidUuidCreate或来自众多使用的框架的各种包装器。在Linux中,有uuid_generate

如果您因某种原因绝对需要自己生成,那么至少要有良好的常识,远离生成v1和v2 UUID。这很难做到正确。相反,应使用v3、v4或v5 UUID。

更新: 在评论中,您提到正在使用Python并链接到此文档。通过查看提供的接口,对于您来说,最简单的选项是通过调用uuid.uuid4()生成v4 UUID(即由随机数据创建的UUID)。

如果您需要(或可以)从某些数据中生成UUID,则可以使用v3(依赖于MD5)或v5(依赖于SHA1)。生成v3或v5 UUID很简单:首先选择要生成的UUID类型(您应该选择v5),然后选择适当的命名空间并使用要用于生成UUID的数据调用函数。例如,如果要散列URL,则应使用NAMESPACE_URL

uuid.uuid3(uuid.NAMESPACE_URL, 'https://ripple.com')

请注意,使用相同URL生成的v5 UUID与此UUID将不同,如下所示:

uuid.uuid5(uuid.NAMESPACE_URL, 'https://ripple.com')

v3和v5 UUID的一个好处是它们应该在实现之间是可互操作的。换句话说,如果两个不同的系统正在使用符合RFC4122的实现,则如果所有其他内容相等(即生成相同版本UUID,具有相同的命名空间和相同的数据),它们将(或至少应该)生成相同的UUID。这个属性在某些情况下可能非常有用(特别是在内容寻址存储方案中),但在您的特定情况下可能不适用。


6
我猜是因为OP没有问:“如何编写自己的UUID生成算法而不是调用大多数现代操作系统提供的UUID生成功能?” - anregen
1
除此之外,我认为这是UUIDv3和v5的很好解释。请看下面我的回答,关于为什么我认为v1可能是一个不错的选择。 - anregen
NAMESPACE_URL是什么?它是一个我可以获取的变量吗?从哪里获取? - stackdave
@stackdave NAMESPACE_URL 是一个 UUID,通常等于 6ba7b811-9dad-11d1-80b4-00c04fd430c8,遵循 RFC-4122 第30页的建议。 - Jamie Ridding
sha256.update(something.getBytes(charset)); sha256.update(somethingElse.getBytes(charset)); byte[] hash = sha256.digest(salt); return UUID.nameUUIDFromBytes(hash).toString();这是v3吗?它们生成相同的UUID吗?符合RFC4122标准吗? - Mohan Radhakrishnan

7
  • 版本 1:使用时间戳和单调计数器生成 UUID。
  • 版本 3:基于某些数据的 MD5 哈希值生成 UUID。
  • 版本 4:随机数据生成 UUID。
  • 版本 5:基于某些数据的 SHA1 哈希值生成 UUID。
  • 版本 6:使用时间戳和单调计数器生成 UUID。
  • 版本 7:使用 Unix 时间戳生成 UUID。
  • 版本 8:使用用户定义数据生成 UUID。

请在Rust 文档中了解更多信息。


3

Postgres文档描述了UUID之间的差异。其中有几个:

V3:

uuid_generate_v3(namespace uuid, name text) - 此函数使用指定的输入名称在给定命名空间中生成版本3 UUID。

V4:

uuid_generate_v4 - 此函数生成一个版本4 UUID,完全基于随机数生成。


2

既然还没有提到:如果您想按创建时间对实体进行排序而无需单独的显式时间戳,则可以使用uuidv1。虽然这不是100%准确且在许多情况下不是最佳选择(由于缺乏明确性),但在某些情况下非常方便,例如当您使用Cassanda数据库时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接