ChatGPT解决这个技术问题 Extra ChatGPT

你什么时候真正被迫使用 UUID 作为设计的一部分?

我真的不明白 UUID 的意义。我知道发生碰撞的概率实际上为零,但实际上为零甚至不是不可能的。

有人可以举一个你别无选择只能使用 UUID 的例子吗?从我看到的所有用途中,我可以看到没有 UUID 的替代设计。当然,设计可能会稍微复杂一些,但至少它的失败概率不为零。

UUID 对我来说闻起来像全局变量。全局变量有很多方法可以简化设计,但它只是懒惰的设计。

任何事情都有非零失败的机会。我会专注于更可能发生的问题(即几乎任何你能想到的问题)而不是 UUID 的冲突
实际上,“有效地为零”几乎是不可能的。
不,它实际上远非不可能
@Pyrolistical 当您开始使用“无限”之类的词时,您已经离开了软件开发的世界。计算机科学理论与编写真正的软件是完全不同的讨论。
我将关闭主要是因为 git 的 sha1 让我相信哈希的好处

B
Bob Aman

我为 Ruby 编写了 UUID 生成器/解析器,所以我认为自己对这个主题相当了解。有四个主要的 UUID 版本:

第 4 版 UUID 本质上只是从加密安全随机数生成器中提取的 16 个字节的随机性,并通过一些位旋转来识别 UUID 版本和变体。这些是极不可能发生冲突的,但是如果使用 PRNG 或者如果你碰巧碰巧真的、真的、真的、真的、真的很倒霉,就会发生这种情况。

第 5 版和第 3 版 UUID 分别使用 SHA1 和 MD5 哈希函数,将命名空间与一段已经唯一的数据结合起来生成 UUID。例如,这将允许您从 URL 生成 UUID。只有当底层哈希函数也有冲突时,这里才有可能发生冲突。

版本 1 UUID 是最常见的。他们使用网卡的 MAC 地址(除非被欺骗,否则应该是唯一的),加上时间戳,再加上通常的位旋转来生成 UUID。对于没有 MAC 地址的机器,6 个节点字节是使用加密安全的随机数生成器生成的。如果按顺序生成两个 UUID 的速度足够快,以至于时间戳与前一个 UUID 匹配,则时间戳会增加 1。除非发生以下情况之一,否则不应发生冲突: MAC 地址被欺骗;一台运行两个不同 UUID 生成应用程序的机器在完全相同的时刻生成 UUID;两台没有网卡或没有用户级别访问MAC地址的机器被赋予相同的随机节点序列,并在完全相同的时刻生成UUID;我们用完字节来表示时间戳并回滚到零。

实际上,这些事件都不会在单个应用程序的 ID 空间内偶然发生。除非您在互联网范围内接受 ID,或者在不受信任的环境中,恶意个人可能会在 ID 冲突的情况下做坏事,否则您不必担心。至关重要的是,如果您碰巧生成了与我相同的版本 4 UUID,在大多数情况下,这并不重要。我在与您完全不同的 ID 空间中生成了 ID。我的应用程序永远不会知道碰撞,所以碰撞无关紧要。坦率地说,在没有恶意行为者的单个应用程序空间中,地球上所有生命的灭绝将在您发生碰撞之前很久就发生,即使在版本 4 UUID 上,即使您每秒生成相当多的 UUID。

此外,2^64 * 16 是 256 艾字节。例如,您需要存储 256 EB 的 ID,然后才有 50% 的机会在单个应用程序空间中发生 ID 冲突。


@Chamnap 我写了 UUIDTools。 UUID 可以转换为整数或其原始字节形式,并且会比二进制小得多。
@eric.frederich 如果发生这种情况,请告诉我。
@BobAman 在 1990 年我在 Aegis 系统上发生了 12 次 UUID 冲突,结果证明是 FPU 有问题,但我想我会让你知道它可能会发生(尽管在过去 30 多年的编程中没有发生过) .很好的解释,顺便说一句,这是我现在给人们的事实上的 UUID 参考帖子:)
@GMasucci 好点。如果硬件不好或者有人决定 /dev/random 应该只返回 4,那么所有的赌注都将被取消。
@kqr您绝对正确,这是生日问题,但是对于n位代码,生日悖论问题减少到2 ^(n / 2),在这种情况下为2 ^ 64,如我的回答中所述.
M
Michael Burr

UUID 给您带来的很难做到的事情是获得唯一标识符,而无需咨询或与中央机构协调。在没有某种托管基础设施的情况下能够获得这样的东西的一般问题是 UUID 解决的问题。

我读过,根据生日悖论,一旦生成了 2^64 个 UUID,发生 UUID 冲突的几率为 50%。现在 2^64 是一个相当大的数字,但 50% 的碰撞几率似乎太冒险了(例如,在有 5% 的碰撞几率之前需要存在多少个 UUID - 即使这看起来概率太大了) .

该分析的问题是双重的:

UUID 不是完全随机的——UUID 的主要组成部分是基于时间和/或位置的。因此,为了真正有机会发生碰撞,需要从不同的 UUID 生成器同时生成碰撞的 UUID。我想说的是,虽然有可能同时生成多个 UUID,但有足够多的其他垃圾(包括位置信息或随机位)使得这组非常小的 UUID 之间发生冲突的可能性几乎是不可能的.严格来说,UUID 只需要在可能与之进行比较的其他 UUID 集合中是唯一的。如果您正在生成一个 UUID 以用作数据库键,那么在邪恶的替代宇宙中的其他地方是否使用相同的 UUID 来识别 COM 接口并不重要。就像在半人马座 Alpha-Centauri 上有其他人(或某物)名为“Michael Burr”时不会引起混淆一样。


具体例子? COM/DCE UUID - 没有分配它们的权限,没有人愿意承担责任和/或没有人希望有一个权威。没有可靠链接且没有主控的分布式数据库。
更具体的示例 - 银行应用程序。它安装了多个数据中心,每个国家一个,每个数据中心都有一个数据库。多个安装是为了遵守不同的规定。每个客户在整个集合中只能有一个客户记录......
(上一条评论的继续)您需要有一个中央服务器来生成客户 ID 以用于整体报告和跟踪目的(跨所有安装)或让各个安装生成 UUID 作为客户 ID(显然 UUID 不能用于在报告中)。
当你有 50% 的重复机会时,你已经淹死了。有人指出达到 0.0000001% 几率所需的音量。从 1 到 n 且每次递增 n 的多个自增数据库有效地解决了同一个问题。
获得副本的几率远远低于中央机构在某些关键任务方面失败的几率
D
DanSingerman

任何事情都有非零失败的机会。我会专注于更可能发生的问题(即几乎任何你能想到的问题)而不是 UUID 的冲突


应 Pyrolistical 的要求添加为答案
R
Rex M

强调“合理地”,或者,正如你所说的,“有效地”:现实世界的运作方式已经足够好。弥补“几乎独一无二”和“真正独一无二”之间的差距所涉及的计算工作量是巨大的。唯一性是一条收益递减的曲线。在这条曲线上的某个点,在“足够独特”仍然可以负担得起的地方之间有一条线,然后我们的曲线非常陡峭。添加更多独特性的成本变得相当大。无限的独特性具有无限的成本。

相对而言,UUID/GUID 是一种计算上快速且简单的方式来生成可以合理假设为普遍唯一的 ID。这在许多需要集成来自以前未连接系统的数据的系统中非常重要。例如:如果您有一个在两个不同平台上运行的内容管理系统,但有时需要将内容从一个系统导入另一个系统。您不希望 ID 更改,因此系统 A 中的数据之间的引用保持不变,但您不希望与系统 B 中创建的数据发生任何冲突。UUID 解决了这个问题。


解决方案。不要偷懒并更新参考资料。做对了。
这与懒惰无关 - 如果策略是项目的 ID 被认为是永久且不可变的,则 ID 不会更改。因此,您希望 ID 从一开始就是唯一的,并且您希望在不要求所有系统从一开始就以某种方式连接的情况下做到这一点。
那么你需要上下文。如果您有两组可能发生冲突的唯一 ID,则需要高级上下文来将它们分开
或者,您可以构建一个使用 UUID 的系统,然后将其运送、出售,赚取一百万美元,并且永远不会听到任何关于两个 ID 冲突的投诉,因为它不会发生。
R
Rob W

创建 UUID 从来都不是绝对必要的。然而,有一个标准是很方便的,在这个标准中,离线用户每个人都可以生成一个碰撞概率非常低的东西的密钥。

这可以帮助解决数据库复制等问题......

在线用户很容易为某些东西生成唯一的密钥,而不会产生开销或冲突的可能性,但这不是 UUID 的用途。

无论如何,关于碰撞概率的一句话,取自维基百科:

从这些数字来看,一个人每年被陨石击中的风险估计为 170 亿分之一,相当于在一年内创建几十万亿个 UUID 并有一个重复的几率。换句话说,仅在接下来的 100 年每秒生成 10 亿个 UUID 之后,仅创建一个副本的概率约为 50%。


很简单,不要让离线用户生成密钥。在系统上线之前分配临时密钥,以便生成真正的密钥。
在我看来,这是一个非常有用的答案......我自己将提供某种与概率的类比,因为 OP 似乎并没有完全理解它的含义,但你似乎已经做到了。
我安静地理解概率实际上为零。对我来说,使用 UUID 是一种懒惰的设计,我只是想看看你是否总是可以避免它
这很公平,只要您看到即使在最极端的情况下也需要考虑低概率,我现在假设您会这样做。
u
user21714

还有一个非零概率,你体内的每个粒子都会同时穿过你坐的椅子,你会突然发现自己坐在地板上。

你担心吗?


当然不是,这不是我可以控制的,但我可以设计。
@Pyrolistical 真的,我的意思是你不担心的原因吗?那你就很奇怪了。而且,你是不对的。你可以控制它。如果你增加了几磅,你就会大大降低发生这种事件的可能性。那么,你认为你应该增肥吗? :-)
J
Johnno Nolan

一个典型的例子是当您在两个数据库之间进行复制时。

DB(A) 插入一条 int ID 为 10 的记录,同时 DB(B) 创建一条 ID 为 10 的记录。这是一个冲突。

使用 UUID 不会发生这种情况,因为它们不会匹配。 (几乎肯定)


好的,然后让 DB A 使用偶数 ID,而 DB B 使用奇数 ID。完成,没有 UUID。
使用三个 DB,使用 3 个倍数 LOL
如果您使用 2/3/任何倍数,那么当您稍后将新服务器添加到组合中时会发生什么?您必须协调一个开关,以便在新服务器上使用 n+1 倍数,并将所有旧服务器移至新算法,并且您必须在执行此操作时关闭所有内容以避免冲突算法切换。或者...您可以像其他所有人一样使用 UUID。
比这更糟糕,因为你如何区分 2 的倍数和 4 的倍数?还是 3 的倍数与 6 的倍数?事实上,你必须坚持使用多个素数。布莱赫!只需使用 UUID,它就可以工作。微软、苹果和无数其他公司都依赖并信任他们。
@sidewinderguy,在我们信任的 GUID 中! :)
D
Donal Fellows

我有一个避免 UUID 的方案。在某个地方设置一个服务器并拥有它,这样每当某个软件需要一个通用唯一标识符时,他们就会联系该服务器并分发一个。简单的!

除了这有一些真正的实际问题,即使我们忽略了彻底的恶意。特别是,该服务器可能会出现故障或无法从部分 Internet 访问。处理服务器故障需要复制,而且很难做到正确(请参阅有关 Paxos 算法的文献,了解为什么建立共识很尴尬)而且速度也很慢。此外,如果从网络的特定部分无法访问所有服务器,则连接到该子网的所有客户端都无法执行任何操作,因为它们都将等待新的 ID。

所以......使用一个简单的概率算法来生成它们在地球的生命周期内不太可能发生故障,或者(资助和)构建一个将成为部署 PITA 并经常发生故障的主要基础设施。我知道我会去哪一个。


实际上,UUID 发明的全部意义在于避免使用您的方法。如果您研究 UUID 的历史,您会发现它源自于创建复杂且有意义的计算机网络的最早实验。他们知道网络本质上是不可靠和复杂的。当您知道计算机之间无法进行持续通信时,UUID 是如何在计算机之间协调数据的问题的答案。
@BasilBourque 我在第一段中使用了讽刺,以防它不明显。
C
Community

我没有得到所有关于碰撞可能性的讨论。我不在乎碰撞。不过我关心性能。

https://dba.stackexchange.com/a/119129/33649

UUID 对于非常大的表来说是一场性能灾难。 (200K 行不是“非常大”。)当 CHARCTER SET 为 utf8 时,您的#3 真的很糟糕——CHAR(36) 占用 108 个字节! UUID (GUID) 非常“随机”。将它们用作大型表上的唯一键或主键是非常低效的。这是因为每次插入新的 UUID 或通过 UUID 选择时都必须在表/索引中跳转。当表/索引太大而无法放入缓存时(请参阅 innodb_buffer_pool_size,它必须小于 RAM,通常为 70%),“下一个”UUID 可能不会被缓存,因此磁盘命中速度很慢。当表/索引是缓存的 20 倍时,只有 1/20(5%)的命中被缓存——你是 I/O 绑定的。所以,不要使用 UUID,除非你有“小”表,或者你真的需要它们,因为从不同的地方生成唯一的 id(并且还没有想出另一种方法)。有关 UUID 的更多信息:http://mysql.rjweb.org/doc.php/uuid(它包括用于在标准 36 字符 UUID 和 BINARY(16) 之间进行转换的函数。)同时具有 UNIQUE AUTO_INCREMENT 和 UNIQUE UUID表是浪费。发生 INSERT 时,必须检查所有唯一/主键是否重复。任一唯一键都足以满足 InnoDB 拥有主键的要求。 BINARY(16)(16 字节)有点庞大(反对将其作为 PK 的论据),但还不错。当您有辅助键时,体积很重要。 InnoDB 默默地将 PK 附加到每个辅助键的末尾。这里的主要教训是最小化辅助键的数量,尤其是对于非常大的表。比较:INT UNSIGNED 为 4 字节,范围为 0..4 亿。 BIGINT 为 8 个字节。


M
Mirko Klemm

如果您只是查看替代方案,例如对于一个简单的数据库应用程序,每次创建新对象之前都必须查询数据库,您很快就会发现使用 UUID 可以有效地降低系统的复杂性。授予 - 如果您使用 int 键,则为 32 位,它将存储在 128 位 UUID 的四分之一中。授予 - UUID 生成算法比简单地增加一个数字占用更多的计算能力。但谁在乎?管理“权限”以分配其他唯一编号的开销很容易超过数量级,具体取决于您预期的唯一性 ID 空间。


J
Johnno Nolan

关于 UUID==惰性设计

我不同意它关于挑选你的战斗。如果重复的 UUID 在统计上是不可能的并且数学证明了,那么为什么要担心呢?花时间围绕您的小型 N UUID 生成系统进行设计是不切实际的,总有十几种其他方法可以改进您的系统。


P
Paul Tomblin

在我的上一份工作中,我们从第三方获取了使用 UUID 唯一标识的对象。我放入了一个 UUID->long integer 查找表并使用 long integer 作为我的主键,因为这样更快。


是的,第三方强迫您使用 UUID 是我不想讨论的另一个问题。假设您可以控制是否使用 UUID。
好吧,“长整数”(128 位)实际上就是 UUID。它仅显示为供人类使用的字符串。有时它可能会以这种方式传输,但对于存储和索引,它肯定会像您发现的那样以整数形式更快。
D
Davy8

使用第 1 版算法,在从同一 MAC 地址生成的每毫秒少于 10 个 UUID 的约束下,似乎不可能发生冲突

从概念上讲,UUID 的原始(版本 1)生成方案是将 UUID 版本与生成 UUID 的计算机的 MAC 地址以及自西方采用公历以来的 100 纳秒间隔数连接起来.在实践中,实际算法更复杂。该方案被批评为不够“不透明”;它揭示了生成 UUID 的计算机的身份以及它生成的时间。

如果我误解了它的工作原理,请有人纠正我


版本很多,很多软件系统(例如Java)不能使用版本1,因为它没有纯Java方式来访问mac地址。
关于 Java 无法获取 MAC 地址:不完全正确。有解决方法。您可以通过配置文件手动设置生成器使用的 MAC 地址。您还可以调用 ifconfig 并解析输出。我编写的 Ruby UUID 生成器使用了这两种方法。
此外,如我的回答中所述,如果您无法获得版本 1 UUID 的 MAC 地址,则根据 RFC 4122 的第 4.5 节,您可以使用 6 个随机字节。所以即使您不想使用其中任何一个对于 Java 的两种解决方法,您仍然可以生成有效的版本 1 UUID。
MS GUID 只是随机数。它们不再有任何 MAC 部分,因为这使得对服务器的 MAC 地址进行逆向工程成为可能(结果证明这是非常危险的)。
I
Iain Duncan

对于那些说 UUID 是糟糕的设计的人,因为它们可能(以某种可笑的小概率)发生冲突,而您的数据库生成的密钥不会……您知道人为错误的可能性会导致您的数据库生成的密钥发生冲突,因为一些 un - 预见需要远高于 UUID4 冲突的机会。我们知道,如果重新创建数据库,它将再次从 1 开始 ids,当我们确定永远不需要重新创建表时,我们中有多少人不得不重新创建表?当任何一天未知的未知事物开始出现问题时,我会把钱花在 UUID 安全上。


S
StephenS

除了必须使用需要 UUID 的其他人的 API 的情况之外,当然还有另一种解决方案。但是这些替代方案能解决 UUID 的所有问题吗?当您可以一次解决所有问题时,您最终会添加更多层的hack,每层解决一个不同的问题吗?

是的,理论上 UUID 有可能发生冲突。正如其他人所指出的那样,它不太可能达到不值得考虑的程度。迄今为止从未发生过,而且很可能永远不会发生。忘掉它。

避免冲突最“明显”的方法是让单个服务器在每次插入时生成唯一的 ID,这显然会产生严重的性能问题,并且根本无法解决离线生成问题。哎呀。

另一个“显而易见”的解决方案是一个中央机构,它提前分发唯一编号块,这本质上是 UUID V1 通过使用生成器的 MAC 地址(通过 IEEE OUI)所做的。但是重复的 MAC 地址确实会发生,因为每个中央机构最终都会搞砸,所以在实践中,这比 UUID V4 冲突更有可能发生。哎呀。

反对使用 UUID 的最佳论据是它们“太大”,但(显着)较小的方案将不可避免地无法解决最有趣的问题; UUID 的大小是它们在解决这些问题时有用的固有副作用。

您的问题可能不够大,不足以需要 UUID 提供的功能,在这种情况下,请随意使用其他东西。但是,如果您的问题出乎意料地增长(而且大多数情况如此),那么您最终会在以后切换——并因为一开始就没有使用它们而自责。当为成功而设计同样容易时,为什么要为失败而设计呢?


k
keyser

UUID 体现了与全局变量相关的所有不良编码实践,更糟糕的是,因为它们是超全局变量,可以分布在不同的工具包中。

最近遇到这样的问题,用一个确切的替换型号替换打印机,发现没有一个客户端软件可以工作。


很高兴我们生活在一个仍然关注事实而不是随机意见的社会中,否则我们所有人都会因为堆栈溢出而失业。 :)

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅