问题:什么时候应该在python中使用uuid.uuid1()和uuid.uuid4()?
uuid1()
:
根据主机ID,序列号和当前时间生成UUID
uuid4()
:
生成随机UUID。
因此,uuid1
使用机器/序列/时间信息来生成UUID。使用每种方法的利弊是什么?
我知道uuid1()
可能会涉及到隐私问题,因为它基于机器信息。我想知道在选择一个或另一个时是否还有其他细微之处。我uuid4()
现在就使用,因为它是完全随机的UUID。但是我想知道我是否应该使用它uuid1
来减少碰撞的风险。
基本上,我正在寻找人们使用某一种方法与另一种方法的最佳使用技巧。谢谢!
回答 0
uuid1()
确保不会产生任何碰撞(假设您不会同时创建太多碰撞)。如果uuid
计算机与计算机之间没有连接很重要,那么我就不会使用它,因为mac地址已被用来使它在计算机之间具有唯一性。
您可以通过在不到100ns 的时间内创建2 个以上的14 uuid1 来创建重复项,但这对于大多数用例而言都不是问题。
uuid4()
如您所说,生成一个随机的UUID。碰撞的机会确实很小。足够小,您不必担心。问题在于,不良的随机数生成器使其更有可能发生冲突。
鲍勃·阿曼的出色回答很好地总结了这一点。(我建议阅读整个答案。)
坦白说,在没有恶意行为者的单个应用程序空间中,即使在每秒生成大量UUID的情况下,即使在版本4 UUID发生碰撞之前,地球上所有生命的消亡也会发生很久。
回答 1
当你可以考虑一个实例uuid1()
,而不是uuid4()
为当UUID的是在不同的机器生产的,例如,当多个网上交易是在几台机器换算目的的过程。
在这种情况下,例如,由于初始化伪随机数生成器的方式选择不当而导致发生冲突的风险,以及产生的潜在数量更多的UUID使得创建重复ID的可能性更大。
uuid1()
在这种情况下,的另一个兴趣是,最初生成每个GUID的机器都被隐式记录(在UUID的“节点”部分中)。仅在调试时,此信息和时间信息可能会有所帮助。
回答 2
我的团队在使用UUID1进行数据库升级脚本时遇到了麻烦,我们在几分钟内生成了约12万个UUID。UUID冲突导致违反主键约束。
我们已经升级了100台服务器,但是在我们的Amazon EC2实例上,我们几次遇到了这个问题。我怀疑时钟分辨率不佳,切换到UUID4可以为我们解决。
回答 3
使用时要注意的一件事uuid1
,如果使用默认调用(不提供clock_seq
参数),则有可能发生冲突:您只有14位的随机性(在100ns内生成18个条目会给您大约1%的冲突机会,请参见生日悖论/攻击)。在大多数情况下,该问题永远不会发生,但是在时钟分辨率较差的虚拟机上,它会咬你。
回答 4
也许没有提到的是本地性。
MAC地址或基于时间的排序(UUID1)可以提高数据库性能,因为与随机分布的数字(UUID4)相比,将数字更紧密地排序在一起的工作量更少(请参见此处)。
第二个相关问题是,即使原始数据丢失或未显式存储,使用UUID1仍可用于调试(这显然与OP提到的隐私问题相冲突)。
回答 5
除了可接受的答案外,还有在某些情况下有用的第三种选择:
带有随机MAC的v1(“ v1mc”)
通过故意生成带有随机广播MAC地址的v1 UUID(v1规范允许),可以在v1和v4之间进行混合。生成的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)