本文目录
什么是 UUID?
UUID(通用唯一标识符)是一个 128 位的值,用于在计算机系统中唯一地标识信息。它以 32 个十六进制数字书写,分为五组、以连字符分隔,形如 550e8400-e29b-41d4-a716-446655440000。
UUID 的设计目标是在无需中央注册机构的情况下实现全局唯一。这使其非常适合分布式系统——多个节点可以各自独立地生成标识符,而永远不会发生冲突。
UUID 版本详解
UUID 标准定义了多个版本,每个版本采用不同的生成方式。版本号出现在第 13 个字符处(也就是第三组的第一位数字)。
- 版本 1(v1)—— 基于时间:将当前时间戳与生成机器的 MAC 地址组合在一起。可以保证唯一性,但会泄露硬件信息
- 版本 3(v3)—— 基于名称并使用 MD5:通过对命名空间和名称进行 MD5 哈希,生成确定性的 UUID。相同的输入总是产生相同的 UUID
- 版本 4(v4)—— 随机:使用最广泛的版本。除版本号和变体字段外的所有位都是随机生成的,可提供约 5.3 × 10 的 36 次方个可能取值
- 版本 5(v5)—— 基于名称并使用 SHA-1:与 v3 类似,但采用 SHA-1 进行哈希。对于新项目,推荐用 v5 而非 v3
- 版本 7(v7)—— 按时间戳排序的随机:一种较新的格式,将 Unix 时间戳与随机位组合,使 UUID 可以按创建时间排序
免费试用 —— 无需注册
校验一个 UUID →UUID 校验的工作原理
校验 UUID 需要同时检查其格式和结构规则。有效的 UUID 必须符合规范的 8-4-4-4-12 十六进制模式,并满足特定版本的约束。
- 格式检查 —— 字符串必须恰好包含 32 个十六进制字符,分为五组、以四个连字符分隔
- 版本检查 —— 第 13 个字符必须是有效的版本号(1、2、3、4、5、6、7 或 8)
- 变体检查 —— 第 17 个字符(第四组的第一位十六进制数字)必须标明 RFC 4122 变体(8、9、a 或 b)
常见使用场景
在现代软件开发的众多领域中,UUID 都是标识符的默认之选。
- 数据库主键 —— UUID 让你可以在客户端直接生成键,无需往返访问数据库,从而使分布式插入变得顺畅无阻
- API 资源标识符 —— 暴露 UUID 而非顺序整数,可以防止枚举攻击,并隐藏业务指标
- 会话与关联 ID —— UUID 可跨微服务追踪请求,让分布式调试成为可能
- 文件与对象命名 —— 云存储系统使用 UUID,以避免多个用户同时上传文件时发生命名冲突
最佳实践
选择合适的 UUID 版本并正确地处理它们,可以帮你避免应用中那些不易察觉的 Bug 和性能问题。
- 通用的随机标识符请使用 v4 —— 它是最常见的选择,且没有任何外部依赖
- 当你需要可按时间排序的标识符时请使用 v7 —— v7 UUID 会按时间先后排序,有助于提升数据库索引性能
- 在数据库中将 UUID 存储为 16 字节的二进制,而非 36 个字符的字符串 —— 这样既节省存储空间,又能加快比较速度
- 对来自外部输入的 UUID 务必进行校验 —— 切勿假设用户提供的字符串格式规范
常见问题
两个 UUID 有可能相同吗?
虽然理论上有可能,但 v4 UUID 发生冲突的概率极其之低。你大约需要生成 27 亿亿(2.7 × 10 的 18 次方)个 UUID,才会有 50% 的几率出现一次冲突。
UUID 区分大小写吗?
不区分。RFC 4122 标准规定 UUID 应以小写形式输出,但各类实现必须将大写和小写十六进制字符视为等价并予以接受。
我应该用 UUID 还是 ULID?
ULID 是 128 位的标识符,可按字典序排序,并采用 Crockford Base32 编码。如果你需要可排序性、又不想引入 UUID v7 的复杂度,ULID 是不错的替代方案。如果与现有系统的兼容性更重要,那就继续使用 UUID。