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

我从文档。中理解了两者之间的差异

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

< p > uuid4(): < br >

.生成一个随机UUID

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

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

基本上,我在寻找人们关于使用其中一种与另一种的最佳实践的建议。谢谢!

137621 次浏览

uuid1()保证不会产生任何碰撞(假设你不会同时创建太多的碰撞)。如果uuid和计算机之间没有连接很重要,我就不会使用它,因为mac地址被用来使它在计算机上是唯一的。

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

uuid4()生成一个随机UUID。碰撞的几率非常非常小。小到你不用担心。问题是,糟糕的随机数生成器更有可能发生碰撞。

这是Bob Aman的精彩回答很好地总结了它。(我建议你阅读完整的答案。)

坦率地说,在单个应用程序空间 如果没有恶意的参与者,那么 地球上所有的生命都会灭绝 发生在你有一个 碰撞,即使在版本4 UUID上, 即使你产生了很多 每秒uuid个数

可以考虑uuid1()而不是uuid4()的一个实例是当uuid在不同的机器上产生时,例如,当多个在线事务在多台机器上处理时,出于扩展目的。

在这种情况下,由于伪随机数生成器初始化方式中的错误选择而产生冲突的风险,以及潜在的更高数量的uuid,使得创建重复id的可能性更大。

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

在使用uuid1时需要注意的一件事是,如果你使用默认调用(没有给出clock_seq参数),你就有可能遇到碰撞:你只有14位的随机性(在100ns内生成18个条目,大约有1%的碰撞几率,参见生日悖论/攻击)。这个问题在大多数情况下都不会发生,但是在时钟分辨率较差的虚拟机上,它会让你很难受。

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

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

也许我们没有提到的是地域性。

MAC地址或基于时间的排序(UUID1)可以提供更高的数据库性能,因为对数字进行更紧密的排序比随机分布的数字(UUID4)更少(参见在这里)。

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

除了公认的答案之外,在某些情况下,还有第三种选择可能有用:

v1与随机MAC ("v1mc")

你可以在v1和amp;通过故意生成带有随机广播MAC地址的v1 uuid(这是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)