ChatGPT解决这个技术问题 Extra ChatGPT

我什么时候应该在 python 中使用 uuid.uuid1() 和 uuid.uuid4()?

我从 docs. 了解两者之间的区别

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

uuid4()
生成随机 UUID。

因此,uuid1 使用机器/序列/时间信息来生成 UUID。使用每种方法的优缺点是什么?

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

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

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

C
Community

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 时没有出现。似乎是直接从马的嘴里说出来的。
如果您在同一节点上每秒生成多个 UUID,uuid1 不一定会生成唯一的 UUID。示例:[uuid.uuid1() for i in range(2)]。当然,除非发生了我想念的奇怪事情。
@Michael:uuid1 有一个序列号(您的示例中的第 4 个元素),因此除非您用完计数器中的所有位,否则您不会发生任何冲突。
@Michael:我尝试研究发生碰撞的情况并添加了我发现的信息。
u
user

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

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

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


M
Mattias Lagergren

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

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


G
Guillaume

使用 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
c
c z

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

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

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


E
Eli Collins

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

带有随机 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() 为clock_seq 使用14 位,最多舍入2 个字节的urandom。 uuid1mc 包装器使用 48 位,应该映射到 urandom 的 6 个字节,每次调用总共消耗 urandom(8)。而 uuid4 每次调用都直接调用 urandom(16)。