通用唯一识别码

電腦用來識別的128位數字

通用唯一识别码(英语:Universally Unique Identifier,缩写:UUID)是用于电脑体系中以识别资讯的一个128位标识符。

UUID按照标准方法生成时,在实际应用中具有唯一性,且不依赖中央机构的注册和分配。UUID重复的概率接近零,可以忽略不计[1][2]

因此,所有人都可以自行建立和使用UUID,而且几乎可以确定其不会与既有的标识符重复。也因为如此,在不同地方产生的UUID可以使用于同一个数据库或同一个频道中,而且几乎不可能重复。

UUID的应用相当普遍,许多计算平台都提供了对于生成和解析UUID的支持。

历史

1990年代, UUID 原本是用于阿波罗电脑网络计算系统,后被用于开放软件基金会分布式运算环境。分布式运算环境UUID的初始设计基于网络计算系统UUID,其设计受 Domain/OS 中定义和使用的(64位)唯一标识符的启发,这是一个也由 阿波罗电脑 设计的操作系统。后来,微软视窗平台采用分布式运算环境设计作为全局唯一标识符(GUID)。

2005年7月,RFC 4122 为 UUID 注册了一个 URN 命名空间,并制定了早期的规范。当 RFC 4122 作为互联网工程任务组标准发布时,国际电信联盟基于先前的标准和 RFC 4122 早期版本标准化了 UUID。

标准

UUID 由开放软件基金会标准化,作为分布式运算环境(DCE)的一部分[3][4]

UUID 被纪录为 ISO/IEC 11578:1996 "Information technology – Open Systems Interconnection – Remote Procedure Call(RPC)" 和后来的 ITU-T Rec. X.667 | ISO / IEC 9834-8:2005 规范的一部分[5]

互联网工程任务组公布了标准 RFC 4122[6],技术上等同于 ITU-T Rec. X.667 | ISO/IEC 9834-8。

格式

在其规范的文本表示中,UUID 的 16 个 8 位字节表示为 32 个十六进制数字,由连字符 '-' 分隔成五组显示,形式为“8-4-4-4-12”总共 36 个字符(32 个十六进制数字和 4 个连字符)。

例如:

123e4567-e89b-12d3-a456-426655440000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

四位数字 M表示 UUID 版本,数字 N的一至三个最高有效位表示 UUID 变体。在例子中,M1 而且 Na10xx2),这意味着此 UUID 是“变体1”、“版本1”UUID;即基于时间的 DCE/RFC 4122 UUID。

规范的 `8-4-4-4-12` 格式字符串基于 UUID 的16个字节的“记录布局”:

UUID 记录结构
名称 长度 (字节) 长度(16进制数字码长) 说明
time_low 4 8 整数:低位 32 bits 时间
time_mid 2 4 整数:中间位 16 bits 时间
time_hi_and_version 2 4 最高有效位中的 4 bits“版本”,后面是高 12 bits 的时间
clock_seq_hi_and_res clock_seq_low 2 4 最高有效位为 1-3 bits“变体”,后跟13-15 bits 时钟序列
node 6 12 48 bits 节点 ID

这些字段对应于“版本1”和“版本2”(基于时间的)UUID中的字段,但是“8-4-4-4-12”的表示适用于所有UUID,即使对于生成方式不同的UUID也是如此。

RFC 4122 第 3 节要求以小写形式生成字符,同时对输入不区分大小写,尽管一些常用的实现违反了此规则。

Microsoft GUID有时会以大括号表示:

{123e4567-e89b-12d3-a456-426655440000}

不应将此格式与“Windows注册表格式”相混淆,后者指的是大括号内的格式。

RFC 4122为UUID定义了统一资源名称(URN)命名空间。作为URN呈现的UUID如下:

urn:uuid:123e4567-e89b-12d3-a456-426655440000

编码

UUID 的二进制编码因系统而异。UUID的变体1是目前世界最常见的UUID,完全以大端序(big-endian)二进制存储与传输 UUID 。

例如,00112233-4455-6677-8899-aabbccddeeff 编码为字节 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff

其他系统,特别是 Microsoft 在其 COM/OLE 库中对 UUID 的字符串表示,使用混合端格式,其中 UUID 的前三组是小端序/小尾序(little-endian),后两组是 大端序/大尾序(big-endian)。

例如,00112233-4455-6677-8899-aabbccddeeff 编码为字节 33 22 11 00 55 44 77 66 88 99 aa bb cc dd ee ff

变体

UUID的变体(variant)字段,占1到3位元。RFC 4122定义了4种变体:

  • 变体 0 (最显著位为0,二进制为0xxx2,十六进制表示为016到716) 用于向后兼容已经过时的1988年开发的 Apollo 网络计算系统(NCS)1.5 UUID 格式。 前6字节是48位元时间戳(从1980年1月1日UTC开始的4微秒的滴答数),随后2个字节保留,再1个字节是地址族(address family,使用了0..13个情形),最后7个字节是主机ID。这类似于UUID的版本1.[7]
  • 变体 1 (二进制为10xx2,十六进制为816到b16),定义在RFC 4122/DCE 1.1 UUIDs, 或"Leach–Salz" UUID。它是按照大端序作为二进制存储与传输。
  • 变体 2 (二进制为110x2,十六进制为c16或d16),RFC称“保留,微软公司向后兼容”。早期的Microsoft Windows平台的GUID使用该格式。和完全使用大端序的变体 1 不同,变体 2 其中一部分按照小端序作为二进制存储与传输。
  • 形如111x2保留未使用。

目前的UUID规范使用变体1和2。在文字表示上,两种变体只有代表变体的位元不同[6]。上面的字段也定义了两种变体之间的字节转换。前三个字段是无正负号的32和16位数字,需要进行转换,而后两个字段是由未解释的字节组成,不需要进行转换。这种转换同样适用于版本3、4和5,其中的规范字段与UUID的内容无关[6]

虽然一些重要的GUID名义上是变体2的UUID,例如组件对象模型(Component Object Model)IUnknown接口的标识符,但是在微软Windows软件中所生成和使用的、被称为“GUID”的许多标识符是使用标准的变体1的RFC 4122/DCE 1.1大端序UUID。目前,Microsoft guidgen工具软件产生变体1的结果。某些微软文档[8]称GUID与UUID是同义词,如同RFC 4122中表示UUID“也被称作GUID”。这些文件表明了虽然“GUID”最初指代微软所使用的其中一种UUID变体,但现在已经成为UUID的另一个名称,含括变体1和2。

版本

对于“变体(variants)1”和“变体2”,标准中定义了五个版本(versions),并且在特定用例中某些版本可能比其他版本更合适。

版本由字符串中的 M 指示。

版本1的UUID是根据时间和节点ID(通常是MAC地址)生成;版本2的UUID是根据标识符(通常是组或用户ID)、时间和节点ID生成;版本3、版本5透过对命名空间(namespace)标识符和名称进行散列生成确定性的UUID;版本4的UUID则使用随机性伪随机性生成。

Nil UUID

Nil UUID是一个特例,值为 00000000-0000-0000-0000-000000000000 ;也就是说,所有位都设置为 0。

版本1(日期时间和MAC地址)

版本1的UUID,是根据 60-bit 的时间戳和节点(生成UUID的电脑)的48-bit MAC地址而生成的。

时间戳的是这样计算的:自公历首次于天主教会和教皇国以外的地方使用的日期,也就是协调世界时(UTC)1582年10月15日午夜算起,每经过100纳秒时间戳加1。RFC 4122声明时间值在公元3400年左右算术溢出[6]:3,取决于所使用的算法,代表此 60-bit 时间戳是有符号数量。但是,某些软件(如libuuid库)将时间戳视为无符号,把溢出时间推迟至公元5236年[9]。ITU-T Rec. X.667所定义的溢出时间为公元3603年[10]:v

13-bit 或 14-bit“无统一”(uniquifying)时钟序列扩展了时间戳,以便处理处理器时钟不能足够快地前进的情况,或者每个节点有多个处理器和 UUID 生成器的情况。对于每个“版本1”UUID 对应于空间(节点)和时间(间隔和时钟序列)中的单个点,两个正确生成的“版本1”UUID 无意中相同的可能性实际上为零。由于时间和时钟序列总共74位,每个节点 id 可以生成    或 18 sextillion)个“版本1”UUID,每个节点 id 的最大平均速率为每秒 1630 亿[6]

与其他 UUID 版本相比,基于来自网卡的 MAC 地址的“版本1”和“版本2”UUID,部分依赖于由中央注册机构发布的标识符,即由 IEEE 发布给网络装置制造商的 MAC 地址的组织唯一标识符(OUI)[11]。基于网卡MAC地址的“版本1”和“版本2”UUID 的唯一性还取决于网卡制造商正确地为其卡分配唯一的MAC地址,这与其他制造过程一样容易出错。此外,某些操作系统允许终端用户自定义MAC地址,例如OpenWRT[12]

使用节点的网络MAC地址作为节点ID,代表可以透过版本1的UUID逆向找到创建它的电脑。透过在文件中嵌入UUID,可以实现追踪到创建或修改这些文件的电脑。在定位 Melissa 病毒的创建者时就使用了这个隐私漏洞[13]

如果节点没有或不希望暴露MAC地址,RFC 4122 确实允许“版本1”(或2)UUID 中的 MAC 地址被随机的48位节点ID替换。在这种情况下,RFC要求节点ID的第一个八位字节的最低有效位应设置为1[6],这对应于MAC地址中的多播位,设置它是用于区分随机生成节点ID的UUID和基于来自网卡的MAC地址的UUID,网卡通常具有单播MAC地址[6]

版本2(日期时间和MAC地址,DCE安全版本)

RFC 4122 保留了版本2的UUID用于“DCE security”;但并没有提供任何细节。因此,许多 UUID 实现省略了“版本2”。但是,“版本2”UUID 的规范由 DCE 1.1 身份验证和安全服务规范提供[4]

“版本2”UUID 类似于“版本1”,除了时钟序列的最低有效8 bits 被“本地域(local domain)”号替换,并且时间戳的最低有效32 bits 由在指定本地域内有意义的整数标识符替换。在 POSIX 系统上,本地域号 0 和 1 分别用于用户 ID(UIDs)和组 ID(GIDs),其他本地域号用于站点定义[4]。在非 POSIX 系统上,所有本地域号都是站点定义的。

在 UUID 中包含 40 位元的域或标识符(domain/identifier)是有代价的。一方面,40 位元允许每个节点ID有大约1万亿个域或标识符的值。另一方面,由于时钟值被截断为28个最高有效位,有别于版本1中的60位,版本2的UUID中的时钟也改成每429.49秒跳动(tick)一次,略多于7分钟,而不是版本1中的每100纳秒;并且,版本2的时钟序列仅有6位元,版本1中则有14位;每7分钟时钟周期内,每个节点、域或标识符只能生成64个唯一的UUID,而版本1的时钟序列值为16,384个[14]。因此,版本2可能不适合用于以节点、域或标识符在约7秒以上1次的速率下生成 UUID 的情况。

版本3和版本5(基于命名空间名称)

“版本3”和“版本5”的 UUID 透过散列(hashing)命名空间标识符和名称生成。版本3使用 MD5 作为散列算法,版本5则使用 SHA1[6]

名称空间标识符本身就是一个 UUID。该规范提供了 UUID 用来表示命名空间为了统一资源定位符(URLs),完整域名、对象标识符和 X.500;但任何所需的UUID都可以用作命名空间指示符。

要确定与给定命名空间和名称对应的版本3的UUID,命名空间的 UUID 将转换为字节串,后面加上输入名称,然后用 MD5 进行散列,产生 128 位元。然后将六或七位替换为固定值,即 4 位元的版本号(例如“版本3”的 0011),以及 2 或 3 位元的 UUID 变体号(例如 10 代表RFC 4122的UUID,或 110 代表传统 Microsoft GUID)。由于预定了6到7位元,因此只有121或122位元用于维持 UUID 的唯一性。

版本5的UUID 和上面类似,但使用 SHA1 而不是 MD5。由于 SHA1 生成 160 位元的摘要,因此在替换版本号和变体号之前会把摘要截断为 128 位元。

版本3和版本5的UUID具有一个特性:相同名称空间和名称将映射到同一个UUID;然而,即使已知其中一项,也无法透过暴力搜索之外的方法从UUID逆向推导出另外一项。RFC 4122 推荐使用版本5(SHA1)而不是版本3(MD5),并建议不要使用任一版本的 UUID 作为安全凭证[6]

版本4(随机)

版本4的UUID是随机生成的。与其他 UUID 一样,其中4位用于代表“版本4”,2到3位元代表变体号(102 或 1102 分别用于变体 1 和 2)。因此,对于变体1(即大多数 UUID),随机生成的版本4的UUID会保留6位元用于表示变体号和版本号,其余122位元用于随机生成,故版本4变体1的UUID共计有   (5.3 undecillion)个。版本4变体2的UUID(传统GUID)则为变体1的一半,因为可用的随机位少一个,变量消耗 3 位元。

一些伪随机数发生器缺少必要的熵来产生足够的伪随机数。例如,使用伪随机数生成器的 WinAPI GUID 生成器已被证明可生成遵循可预测模式的 UUID。 RFC 4122 建议“在各种主机上生成 UUID 的分布式应用程式必须愿意依赖所有主机上的随机数源。如果这不可行,则应使用名称空间变体。”

冲突

当多次生成相同的 UUID 并将其分配给不同的指示对象时,就会发生冲突。对于使用来自网卡的唯一MAC地址的标准版本1和2的UUID,只有当实施与标准不同时才可能发生冲突,无论是无意还是故意。

与使用MAC地址生成的版本1和版本2相比,使用随机生成的节点ID的版本1和版本2、基于散列的版本3和版本5,以及随机生成的版本4的UUID,即使实现上没有问题也可能发生冲突,但可能性很小,通常可以忽略。可以基于对生日问题的分析来精确地计算该概率[15]

例如,如果要有50%的几率至少发生一次冲突,需要生成至少 个版本4的UUID,计算如下[16]

 

这个数字相当于每秒产生 10 亿个 UUID 持续 85 年。每个 UUID 长度为 16 字节,这么多 UUID 的文件大小约为 45 艾字节(EB),比目前存在的最大数据库大很多倍,它们都在数百PB的数量级。

若要使发生冲突的几率为p,至少必须生成多少个版本4的UUID可由下式近似计算:

 

因此,在 103 万亿个版本4 UUID 中找到重复的概率是  (十亿分之一)。

使用

文件系统

重要用途包括 ext2/ext3/ext4 文件系统用户空间工具(e2fsprogs 使用 util-linux 提供的 libuuid)、LUKS 加密分区、GNOME、KDE 和 Mac OS X,其中大部分源自 曹子德(Theodore Ts'o)的实现[9]

Solaris 中 UUID 的一种用途(使用开放软件基金会的实现)是识别正在运行的操作系统实例,以便在内核崩溃的情况下将故障转储数据与故障管理事件配对[17]

分区标签和分区UUID都存储于超区块中。两者皆为文件系统的一部分,而不是分区的一部分。例如,ext2-ext4包含UUID,而NTFS或FAT32则没有。

超区块是文件系统的一部分,因此被完全包含在分区中,因此如果你执行dd if=/dev/sda1 of=/dev/sdb1,sda1和sdb1都会拥有相同的标签和UUID。

COM

Microsoft的组件对象模型(COM)中使用了几种GUID :

  • IID - 接口标识符;(在系统上注册的接口标识符存储在Windows注册表中的[HKEY_CLASSES_ROOT\Interface][18]
  • CLSID - 类标识符;(存储在[HKEY_CLASSES_ROOT\CLSID]
  • LIBID - 类型库标识符;(存储于[HKEY_CLASSES_ROOT\TypeLib][19]
  • CATID - 类别标识符;(它在一个类中的存在将其识别为属于某些类别类别,列于[HKEY_CLASSES_ROOT\Component Categories][20]

作为数据库主键

UUID 通常用作数据库表中的唯一键。

Microsoft SQL Server 版本4 Transact-SQL 中的 NEWID 函数会返回标准随机版本4的UUID,而 NEWSEQUENTIALID 函数返回类似于 UUID 的 128 位标识符,这些 UUID 会依序递增,直到下次系统重启[21]

另一方面,尽管名称如此,但 Oracle Database SYS_GUID 函数不会返回标准 GUID;相反,它根据主机标识符和进程或线程标识符返回一个16字节的 128 位 RAW 值,有点类似于 GUID[22]

PostgreSQL 包含一个 UUID 数据类型[23],并且可以通过使用模块中的函数生成大多数版本的UUID[24][25]

MySQL 提供了一个 UUID 函数,它生成标准的版本1 UUID[26]

当 UUID 用作主键时,版本3、4和5 UUID 的随机性以及 版本1和2 UUID 内的字段的排序可能会产生数据库定位或性能问题。例如,2002年 Jimmy Nilsson 报告说,当用作主键的版本4 UUID 被修改为包含基于系统时间的非随机后缀时,Microsoft SQL Server的性能显着提高。Nilsson 承认,这种所谓的“COMB”(组合时间和GUID)方法使UUID非标准并且更有可能被复制,但 Nilsson 仅要求在应用程式中的唯一性[27]。透过重新排序和编码版本1和版本2的UUID,将时间戳放在最前面,可以避免插入所造成的性能损失[28]

诸如Laravel这样的部分网络框架支持“时间戳优先”的UUID,可以将UUID有效存储于索引数据库中。这种UUID是版本4格式的COMB UUID,但其中前48位组成了一个时间戳,就像版本1的UUID一样[29][30]。其他基于COMB UUID概念的指定格式包括:

  • ULID,其抛弃了用于表示版本4的4位,并且默认使用base32编码[31]
  • UUID版本6到8是三种COMB UUID格式的正式提议。

参见

参考文献

  1. ^ Universally Unique Identifiers (UUID). H2. [21 March 2021]. (原始内容存档于2006-07-09). 
  2. ^ ITU-T Recommendation X.667页面存档备份,存于互联网档案馆): Generation and registration of Universally Unique Identifiers (UUIDs) and their use as ASN.1 Object Identifier components. Standard. October 2012.
  3. ^ CDE 1.1: Remote Procedure Call. The Open Group. 1997 [2022-10-17]. (原始内容存档于2010-07-07). 
  4. ^ 4.0 4.1 4.2 DCE 1.1: Authentication and Security Services. The Open Group. 1997 [2022-10-17]. (原始内容存档于2010-12-07). 
  5. ^ ITU-T Study Group 17 - Object Identifiers (OID) and Registration Authorities Recommendations. ITU.int. [2016-12-20]. (原始内容存档于2010-08-20). 
  6. ^ 6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 Leach, P.; Mealling, M.; Salz, R.. A Universally Unique IDentifier (UUID) URN Namespace. Internet Engineering Task Force. 2005 [2017-01-17]. RFC 4122. 
  7. ^ uuid.c. [2020-10-09]. (原始内容存档于2021-02-24). 
  8. ^ Globally Unique Identifiers. Microsoft Developer Network. Microsoft. [2020-10-09]. (原始内容存档于2019-02-13). 
  9. ^ 9.0 9.1 ext2/e2fsprogs.git - Ext2/3/4 filesystem userspace utilities. Kernel.org. [9 January 2017]. [失效链接]
  10. ^ Recommendation ITU-T X.667. www.itu.int. October 2012 [19 December 2020]. (原始内容存档于2022-10-17). 
  11. ^ Registration Authority. IEEE Standards Association. [2022-10-17]. (原始内容存档于2018-03-05). 
  12. ^ MAC Address Setup. OpenWRT. 15 September 2021 [2022-10-17]. (原始内容存档于2022-10-18). 
  13. ^ Reiter, Luke. Tracking Melissa's Alter Egos. ZDNet. 1999-04-02 [2017-01-16]. (原始内容存档于2012-10-21). 
  14. ^ Kuchling, A. M. What's New in Python 2.5. Python.org. [23 January 2016]. (原始内容存档于2021-02-07). 
  15. ^ Jesus, Paulo; Baquero, Carlos; Almaeida, Paulo. ID Generation in Mobile Environments (PDF). Repositorium.Sdum.Uminho.pt. [2022-10-17]. (原始内容存档 (PDF)于2022-10-17). 
  16. ^ Mathis, Frank H. A Generalized Birthday Problem. SIAM Review. June 1991, 33 (2): 265–270. CiteSeerX 10.1.1.5.5851 . ISSN 0036-1445. JSTOR 2031144. OCLC 37699182. doi:10.1137/1033051. 
  17. ^ Crashdump Restructuring in Solaris. Blogs.Oracle.com. Oracle. [9 January 2017]. (原始内容存档于2016-06-29). 
  18. ^ Interface Pointers and Interfaces. Windows Dev Center - Desktop app technologies. Microsoft. [15 December 2015]. (原始内容存档于2017-07-06). You reference an interface at run time with a globally unique interface identifier (IID). This IID, which is a specific instance of a globally unique identifier (GUID) supported by COM, allows a client to ask an object precisely whether it supports the semantics of the interface, without unnecessary overhead and without the confusion that could arise in a system from having multiple versions of the same interface with the same name. 
  19. ^ Registering a Type Library. Microsoft Developer Network. Microsoft. [15 December 2015]. (原始内容存档于2017-09-28). 
  20. ^ Categorizing by Component Capabilities. Windows Dev Center - Desktop app technologies. Microsoft. [15 December 2015]. (原始内容存档于2017-11-22). A listing of the CATIDs and the human-readable names is stored in a well-known location in the registry. 
  21. ^ NEWSEQUENTIALID (Transact-SQL). Microsoft Developer Network. Microsoft. 2015-08-08 [2017-01-14]. (原始内容存档于2010-06-06). 
  22. ^ Oracle Database SQL Reference. Oracle. [2022-10-17]. (原始内容存档于2022-10-17). 
  23. ^ Section 8.12 UUID Type. PostgreSQL 9.4.10 Documentation. PostgreSQL Global Development Group. 13 February 2020 [2022-10-17]. (原始内容存档于2018-03-09). 
  24. ^ uuid-ossp. PostgreSQL: Documentation: 9.6. PostgreSQL Global Development Group. 12 August 2021 [2022-10-17]. (原始内容存档于2018-03-09). 
  25. ^ pgcrypto. PostgreSQL: Documentation: 9.6. PostgreSQL Global Development Group. 12 August 2021 [2022-10-17]. (原始内容存档于2018-03-09). 
  26. ^ Section 13.20 Miscellaneous Functions. MySQL 5.7 Reference Manual. Oracle Corporation. [2022-10-17]. (原始内容存档于2022-11-06). 
  27. ^ Nilsson, Jimmy. InformIT. InformIT. 2002-03-08 [2012-06-20]. (原始内容存档于2010-08-26). 
  28. ^ Storing UUID Values in MySQL. Percona. 2014-12-19 [2021-02-10]. (原始内容存档于2020-11-29). 
  29. ^ Helpers - Laravel - The PHP Framework For Web Artisans. Laravel.com. [2022-10-17]. (原始内容存档于2022-10-21). 
  30. ^ Cabrera, Italo Baeza. Laravel: The mysterious "Ordered UUID". Medium. 31 January 2020 (英语). 
  31. ^ Universally Unique Lexicographically Sortable Identifier. GitHub. ULID. 10 May 2021 [2022-10-17]. (原始内容存档于2022-12-22).