uuid的版本选择和使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uuid的版本选择和使用相关的知识,希望对你有一定的参考价值。

参考技术A UUID,是Universally Unique Identifier的缩写,UUID出现的目的,是为了让分布式系统可以不借助中心节点,就可以生成UUID来标识一些唯一的信息;

GUID,是Globally Unique Identifier的缩写,跟UUID是同一个东西,只是来源于微软。

UUID是由一组32位数的16进制数字所构成,是故UUID理论上的总数为16^32 = 2^128,约等于3.4 x 10^38。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。

UUID的标准型式包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的32个字符,如:550e8400-e29b-41d4-a716-446655440000。

UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。

(1)当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。

(2)时钟序列。

(3)全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。

UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique Identifiers)。

UUID的格式是这样的:xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

N那个位置,只会是8,9,a,b

M那个位置,代表版本号,由于UUID的标准实现有5个版本,所以只会是1,2,3,4,5

通过当前时间戳、机器MAC地址生成;

由于在算法中使用了MAC地址,这个版本的UUID可以保证在全球范围的唯一性。

但与此同时,因为它暴露了电脑的MAC地址和生成这个UUID的时间,这就是这个版本UUID被诟病的地方。

DCE安全的UUID和基于时间的UUID算法相同,但会把时间戳的前4位置换为POSIX的UID或GID。

不过,在UUID的规范里面没有明确地指定,所以基本上所有的UUID实现都不会实现这个版本。

由用户指定1个namespace和1个具体的字符串,通过MD5散列,来生成1个UUID;

根据规范描述,这个版本的存在是为了向后兼容?平时这个版本我们也很少用到

根据随机数,或者伪随机数生成UUID。这种UUID产生重复的概率是可以计算出来的,但随机的东西就像是买彩票:你指望它发财是不可能的,但狗屎运通常会在不经意中到来。这个版本应该是平时大家无意中用得最多的版本了;

和版本3一样,不过散列函数换成了SHA1

使用哪个 UUID 版本?

【中文标题】使用哪个 UUID 版本?【英文标题】:Which UUID version to use? 【发布时间】:2013-12-18 23:21:44 【问题描述】:

您应该使用哪个版本的 UUID?我看到很多线程解释了每个版本的含义,但我无法弄清楚什么最适合哪些应用程序。

【问题讨论】:

你的选择是什么? 任何适用于 python 的东西。所以我猜这是docs.python.org/2/library/uuid.html。 1,3,4,5。 如果您对版本 3 和 5 感到好奇,请参阅此问题,Generating v5 UUID. What is name and namespace?。 【参考方案1】:

有两种不同的方式来生成 UUID。

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

版本 1:这会根据网卡 MAC 地址和当前时间生成唯一 ID。如果这些东西中的任何一个以任何方式敏感,请不要使用它。该版本的优势在于,在查看由您信任的机器生成的 UUID 列表时,您可以轻松了解是否有许多 UUID 是由同一台机器生成的,或者推断它们之间的某种时间关系。

版本 4:这些是由随机(或伪随机)数字生成的。如果您只需要生成一个 UUID,这可能就是您想要的。此版本的优势在于,当您调试并查看与 UUID 匹配的一长串信息时,可以更快地发现匹配项。

如果您需要从给定名称生成可重现的 UUID,则需要版本 3 或版本 5。

版本 3:这会根据命名空间和名称的 MD5 哈希生成唯一 ID。如果您需要向后兼容(与从名称生成 UUID 的另一个系统),请使用它。

版本 5:这会根据命名空间和名称的 SHA-1 哈希生成唯一 ID。这是更安全的版本。

【讨论】:

我要补充一点:如果您需要从给定名称生成 reproducible UUID,则需要版本 3 或版本 5。如果您为该算法提供相同的输入,它将生成相同的输出。 在云计算环境(例如 AWS 或 GAE)中,版本 1 的弱点似乎被忽略了。随着时间的推移,可能有数千个不同的 MAC 地址应用于给定应用程序的 UUID 生成器,从而消除了可预测性和/或可追溯性。 @user239558 鉴于 UUID 的目标是其唯一性,UUIDv5 仍然是首选。 关于“不推荐”版本 1 的评论过于简单化。在许多情况下,这些确实很好而且更可取。但是,如果您担心从 UUID 泄露这些信息中的任何一项,这些信息可能会提供给不可信的参与者:(a)创建 UUID 的机器的 MAC 地址,或(b)创建时的日期时间,然后避免使用版本 1。如果这两条信息敏感,那么版本 1 是一个很好的选择。 第 2 版发生了什么?【参考方案2】:

由于尚未提及:如果您希望能够按创建时间对实体进行排序,而无需单独的明确时间戳,则可以使用 uuidv1。虽然这不是 100% 精确,在许多情况下也不是最好的方法(由于缺乏明确性),但在某些情况下它会派上用场,例如当您使用 Cassanda 数据库时。

【讨论】:

【参考方案3】:

Postgres documentation 描述了UUIDs 之间的区别。其中几个:

V3:

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

V4:

uuid_generate_v4 - 此函数生成版本 4 UUID,它完全来自随机数。

【讨论】:

【参考方案4】:

如果您想要一个随机数,请使用随机数库。如果你想要一个有效的 0.00 的唯一标识符......这里还有更多的 0......001% 的碰撞几率,你应该使用 UUIDv1。有关 UUIDv3 和 v5,请参阅 Nick 的帖子。

UUIDv1 不安全。它不应该是。它意味着是唯一的,而不是不可猜测的。 UUIDv1 使用当前时间戳,加上一个机器标识符,再加上一些随机的东西来生成一个永远不会再由该算法生成的数字。这适用于事务 ID(即使每个人都在进行数百万次事务/秒)。

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

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

【讨论】:

除非you generate a billion UUIDs every second for a century and win a coin flip,否则您不会看到两个 UUID 版本 4 实现发生冲突。请记住,set_size 是 2^122,非常大 V4 算法不是串行的,这意味着 v4 生成的前两个 UUID 有可能匹配。仅仅因为有很多选项,并不意味着您必须在生成重复之前用完独特的选项。这可能随时发生。 你没有真正做数学。我们(作为一个物种)每秒不会产生 10 亿个 UUID。因此,距离第一次碰撞(平均)还有 100 年以上的时间。 V4“可能”发生碰撞,但对于大多数用例来说,这种风险非常低,值得冒险。回复:“世界上的两台机器最终会创建相同的 'UUID'v4”,嗯,当然,但这不是问题,因为世界上大多数使用 UUID 的机器在不同的上下文中使用它们。我的意思是,如果我为自己的内部应用程序生成与您为内部应用程序生成的 UUID 相同的 UUID,那么没关系。只有当它们发生在相同的上下文中时,碰撞才有意义。 (请记住,即使在一个应用程序中,许多 UUID 不必在整个应用程序中都是唯一的,只要它们使用的上下文是唯一的) 所以听起来,如果您不需要您的 Guid 是安全的,请使用版本 1。如果您需要它的安全,并且觉得幸运(或者真的,不要觉得不幸运)使用版本4.【参考方案5】:

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

这样做更容易、更安全,而且您可能不需要 自己生成,为什么还要编写实现代码呢?在这种情况下,答案就变成使用你的操作系统、编程语言或框架提供的任何东西。例如,在 Windows 中,有 CoCreateGuid 或 UuidCreate 或可从众多正在使用的框架中获得的各种包装器之一。在 Linux 中有uuid_generate。

如果您出于某种原因绝对需要生成自己的 UUID,那么至少要远离生成 v1 和 v2 UUID。把这些做好是很棘手的。相反,坚持使用 v3、v4 或 v5 UUID。

更新: 在评论中,您提到您正在使用 Python 并链接到 this。查看提供的界面,最简单的选项是通过调用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')

请注意,此 UUID 将不同于同一 URL 的 v5 UUID,其生成方式如下:

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

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

【讨论】:

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

以上是关于uuid的版本选择和使用的主要内容,如果未能解决你的问题,请参考以下文章

使用哪个 UUID 版本?

如何选择主键uuid

XSLT 转换 XML:选择 uuid 并按顺序排序

Appium选择的IOS模拟器UUID在我的桌面上不存在

当与其他用户登录时,它仍然会从无处选择以前的用户 uuid

关于uuid与自增列的选择