【问题标题】:When should I use uuid.uuid1() vs. uuid.uuid4() in python?我什么时候应该在 python 中使用 uuid.uuid1() 和 uuid.uuid4()?
【发布时间】:2010-12-19 14:54:33
【问题描述】:

我从docs.了解两者的区别

uuid1():
根据主机 ID、序列号和当前时间生成 UUID

uuid4():
生成随机 UUID。

所以uuid1 使用机器/序列/时间信息来生成 UUID。各自使用的优缺点是什么?

我知道uuid1() 可能存在隐私问题,因为它基于机器信息。我想知道在选择其中一个时是否有更微妙的地方。我现在只使用uuid4(),因为它是一个完全随机的 UUID。但我想知道我是否应该使用uuid1 来降低碰撞风险。

基本上,我正在寻找人们关于使用一种与另一种的最佳实践的提示。谢谢!

【问题讨论】:

  • 这是 UUID 的另一种方法。虽然碰撞的机会是无限小的 UUID 并不能保证唯一性。为了保证唯一性,您可能希望使用复合键作为 [,]。参与数据共享的每个系统都必须有自己的系统唯一 ID,或者在系统设置期间分配,或者从公共 ID 池中获得。本地 ID 是任何特定系统中的唯一 ID。这涉及更多麻烦,但保证了唯一性。抱歉跑题了,只是想帮忙。
  • 不关心他提到的“隐私问题”

标签: python uuid


【解决方案1】:

除了接受的答案之外,还有第三个选项在某些情况下很有用:

带有随机 MAC 的 v1 ("v1mc")

您可以通过故意生成具有随机广播 MAC 地址的 v1 UUID 来混合 v1 和 v4(这是 v1 规范允许的)。生成的 v1 UUID 是时间相关的(如常规 v1),但缺少所有主机特定信息(如 v4)。它的抗碰撞性也更接近 v4:v1mc = 60 位时间 + 61 个随机位 = 121 个唯一位; v4 = 122 个随机位。

我遇到的第一个地方是 Postgres 的 uuid_generate_v1mc() 函数。从那以后,我使用了以下 python 等效项:

from os import urandom
from uuid import uuid1
_int_from_bytes = int.from_bytes  # py3 only

def uuid1mc():
    # NOTE: The constant here is required by the UUIDv1 spec...
    return uuid1(_int_from_bytes(urandom(6), "big") | 0x010000000000)

(注意:我有一个更长、更快的版本,可以直接创建 UUID 对象;如果有人愿意,可以发布)


在每秒调用量很大的情况下,这有可能耗尽系统随机性。您可以改用 stdlib random 模块(它可能也会更快)。但请注意:攻击者只需几百个 UUID 就可以确定 RNG 状态,从而部分预测未来的 UUID。

import random
from uuid import uuid1

def uuid1mc_insecure():
    return uuid1(random.getrandbits(48) | 0x010000000000)

【讨论】:

  • 似乎这种方法“像”v4(与主机无关),但更糟(更少的位,对 urandom 的依赖等)。与仅 uuid4 相比有什么优势吗?
  • 这主要只是针对 v1 因其基于时间的质量而有用但需要更强的抗碰撞性和主机隐私的情况的升级。一个例子是作为数据库的主键 - 与 v4 相比,v1 uuid 在写入磁盘时具有更好的局部性,具有更有用的自然排序等。但是如果您遇到攻击者预测 2** 的情况61 位是一个安全问题(例如 uuid 是一个随机数),然后 $diety 是的,使用 uuid4 代替(我知道我这样做!)。回复:更糟糕的是因为它使用了 urandom,我不确定你的意思 - 在 python 下,uuid4() 也使用 urandom。
  • 好东西,有道理。很高兴不仅能看到你能做什么(你的代码),还能看到你为什么想要它。回复:urandom,我的意思是你消耗了 2 倍的随机性(uuid1 为 1,urandom 为另一个),所以可以更快地用完系统熵。
  • 实际上大约是 uuid4 的一半:uuid1() 使用 14 位的 clock_seq,最多舍入 2 个字节的 urandom。 uuid1mc 包装器使用 48 位,应该映射到 urandom 的 6 个字节,每次调用总共消耗 urandom(8)。而 uuid4 每次调用都会直接调用 urandom(16)。
【解决方案2】:

也许没有提到的是地方性。

MAC 地址或基于时间的排序 (UUID1) 可以提高数据库性能,因为与随机分布的数字 (UUID4) 相比,将数字排序得更近的工作量更少(请参阅 here)。

第二个相关问题是,使用 UUID1 在调试中可能很有用,即使原始数据丢失或未明确存储(这显然与 OP 提到的隐私问题相冲突)。

【讨论】:

    【解决方案3】:

    我的团队在使用 UUID1 进行数据库升级脚本时遇到了麻烦,我们在几分钟内生成了大约 120k UUID。 UUID 冲突导致违反主键约束。

    我们已经升级了 100 台服务器,但在我们的 Amazon EC2 实例上,我们多次遇到此问题。我怀疑糟糕的时钟分辨率和切换到 UUID4 为我们解决了这个问题。

    【讨论】:

      【解决方案4】:

      使用uuid1 时需要注意的一点,如果您使用默认调用(不提供clock_seq 参数),您就有可能遇到冲突:您只有 14 位随机性(在 100ns 内生成 18 个条目给出你大约有 1% 的碰撞几率看到生日悖论/攻击)。在大多数用例中,这个问题永远不会发生,但在时钟分辨率较差的虚拟机上,它会咬你一口。

      【讨论】:

      • @Guilaume 看到使用clock_seq....的良好实践示例将非常有用。
      • @Guilaume 你是如何计算 1% 的机会的? 14 位随机性意味着如果您每 100 ns 生成 >= 2^14 个 id,则一定会发生冲突,这意味着当您每 100 ns 生成大约 163 个 id 时,发生冲突的几率为 1%
      • @maks 正如我所说,你应该看看birthday paradox
      【解决方案5】:

      uuid1() 保证不会产生任何冲突(假设您不会同时创建太多冲突)。如果uuid 和计算机之间没有连接很重要,我不会使用它,因为 MAC 地址被用来使其在计算机之间具有唯一性。

      您可以通过在 100ns 内创建超过 214 个 uuid1 来创建副本,但这对于大多数用例来说都不是问题。

      uuid4() 如您所说,生成一个随机 UUID。发生碰撞的机会真的非常非常非常小。足够小,你不应该担心它。问题是,糟糕的随机数生成器更容易发生冲突。

      This excellent answer by Bob Aman 总结得很好。 (我建议阅读整个答案。)

      坦率地说,在单个应用程序空间中 没有恶意行为者, 地球上所有生命将灭绝 早在你有一个 碰撞,即使在版本 4 UUID 上, 即使你产生了很多 每秒 UUID。

      【讨论】:

      • 抱歉,我在没有充分研究的情况下发表了评论 - 保留了一些位以防止版本 4 uuid 与版本 1 uuid 发生冲突。我将删除我原来的评论。见tools.ietf.org/html/rfc4122
      • @gs 是的,我正在阅读的内容很有意义。 uuid1 “更独特”,而 uuid4 更匿名。所以基本上使用 uuid1 ,除非你有理由不这样做。 @mark ransom:很棒的答案,当我搜索 uuid1/uuid4 时没有出现。似乎是直接从马的嘴里说出来的。
      • uuid1 如果您在同一节点上每秒生成多个 UUID,则不一定会生成唯一的 UUID。示例:[uuid.uuid1() for i in range(2)]。当然,除非发生了我想念的奇怪事情。
      • @Michael: uuid1 有一个序列号(您的示例中的第 4 个元素),因此除非您用完计数器中的所有位,否则您不会发生任何冲突。
      • @Michael:我尝试研究发生碰撞的情况并添加了我发现的信息。
      【解决方案6】:

      您可能会考虑使用uuid1() 而不是uuid4() 的一个实例是在不同的机器上生成 UUID,例如在多台机器上处理多个在线事务以实现扩展目的时。 p>

      在这种情况下,例如,由于伪随机数生成器的初始化方式选择不当而导致发生冲突的风险,而且产生的 UUID 数量可能更多,从而更有可能创建重复 ID .

      uuid1() 的另一个兴趣在于,在这种情况下,每个 GUID 最初生成的机器都被隐式记录(在 UUID 的“节点”部分)。如果仅用于调试,此信息和时间信息可能会有所帮助。

      【讨论】:

        猜你喜欢
        • 2018-06-26
        • 2016-01-09
        • 2017-01-08
        • 2010-12-30
        • 1970-01-01
        • 1970-01-01
        • 2021-09-07
        • 2018-03-25
        相关资源
        最近更新 更多