免费 UUID 生成器
即时生成随机 UUID v4 值。
快速生成
批量生成
关于 UUID
UUID(通用唯一标识符)是一个 128-bit 标识符,设计用于在空间和时间上保持唯一。最常见的版本 UUID v4 使用随机或伪随机数生成。格式为 8-4-4-4-12 十六进制字符,例如 550e8400-e29b-41d4-a716-446655440000。
四十年历史,从 Apollo 到 RFC 9562
UUID 概念起源于 1980 年代中期的 Apollo Network Computing System(NCS),由 Apollo Computer 的 Paul Leach 与 Rich Salz 设计,用于支持无中央注册的分布式计算。该格式被 1989 年的 Open Software Foundation Distributed Computing Environment(OSF DCE)采用,1995 年作为 ITU-T X.667 / ISO/IEC 9834-8 在国际上标准化。IETF 在 2005 年 7 月把这套规范折进 RFC 4122(Leach、Mealling、Salz),这成为之后两个十年里的规范化参考。RFC 4122 在 2024 年 5 月被 RFC 9562 更新,保留了所有原有版本(v1 到 v5),增加了三个新版本(v6、v7、v8),并正式定义了特殊常量「Nil UUID」(全零)与「Max UUID」(全一)。版本谱系之所以重要,是因为每个版本在不同性质之间做了取舍:基于时间(可排序、会泄露);基于名称(对输入决定);基于随机(通用、不透明);自定义(任你需要)。新应用的现代最佳实践,在主键上已从 v4(随机)转向 v7(时间戳 + 随机),而 v4 仍是那些不希望可排序的不透明标识符的正确答案。
用平实语言讲八个版本
- v1(时间戳 + MAC 地址)。60 位时间戳(自 1582 年公历纪元起的 100 纳秒间隔)加上生成机器的 MAC 地址。主要缺点:它泄露生成机器的 MAC 地址,这是隐私问题。Melissa 病毒的作者 1999 年被广为人知地识别出来,部分就是把 Word 文档里的 v1 UUID 一路追溯到了某台具体的机器。
- v2(DCE security)。v1 的一个变种,包含一个 POSIX UID/GID。在实践中几乎从不使用;为完整性记录在案。
- v3(基于名称,MD5)。由 (namespace UUID + 名称字符串) 的 MD5 哈希派生出的确定性 UUID。同样的输入总是产生同样的 UUID,便于把自然键(URL、域名、distinguished name)翻译成 UUID 形式。
- v4(随机)。122 位随机性(剩下 6 位是版本 + variant 标记)。使用最广的版本,几乎每一个「给我一个 UUID」的库默认都返回它。
- v5(基于名称,SHA-1)。与 v3 相同,但用 SHA-1 替代 MD5。新应用偏向选 v5 而不是 v3,因为 SHA-1 比MD5「破得没那么彻底」,即便两者都已存在已知的碰撞攻击。
- v6(RFC 9562,2024 年 5 月,按时间排序)。把 v1 的时间戳位重新排列,使字典序排序与时间排序一致。解决了「v1 不能按时间排序」这一抱怨;默认仍然会泄露 MAC 地址。
- v7(RFC 9562,2024 年 5 月,Unix 时间戳 + 随机)。前 48 位是以毫秒计的 Unix 时间戳;剩下 74 位是随机的。天然按创建时间排序,在不泄露机器身份的情况下含有时间戳数据,是数据库主键的现代推荐。Postgres 18+ 内建
uuidv7();SQL Server 有性质类似的NEWSEQUENTIALID()。 - v8(自定义)。保留给特定应用的布局。版本字段把它标记为 v8,variant 位也设置正确;其他一切由应用决定。当你需要在 UUID 形状的信封里嵌入自己结构化数据时使用。
为什么 v7 在数据库主键上越来越被偏好,而不是 v4
随机主键(v4 UUID)在那些以主键、用 B 树或类似索引来组织行的数据库中,有充分文档化的性能代价。每一次新插入都落在索引里一个随机位置,这会让索引页碎片化、增加磁盘上的写放大,并把页缓存搅烂,因为最近插入的行散布在许多页里,而不是聚集到一起。顺序主键(自增整数、ULID、v7 UUID)都插入到索引最右边,这会让 working set 保持很小,写放大也最小。这套「随机主键反模式」批评最早可以追溯到 SQL Server 早期围绕 NEWID 与 NEWSEQUENTIALID 的文档,后来又被 Postgres 社区在 v4 vs v7 的语境里重述。代价:v7 会泄露每一行的创建时间,在某些应用中这可能是一种隐私或信息泄露顾虑(比如读一个账号的 UUID 就能判断它何时创建)。对大多数应用来说,性能收益胜过时间戳泄露;对高隐私应用,v4 仍是正确答案。
碰撞概率,生日悖论的算术
UUID v4 有 122 位随机性,大约给出 5.3 × 1036 个可能值。生日悖论告诉我们,要让任意一对出现碰撞的概率达到 50%,大约需要命名空间大小的平方根那么多,大约 2.71 × 1018 个 UUID。换成人能感受的话:如果你每秒持续生成 10 亿个 UUID,大概要 86 年才有 50% 的机会出现一次碰撞。对普通的应用级生成速率(每天数千或数百万)来说,实际碰撞风险为零。现实系统中出现「重复 UUID」最常见的原因,是某个有 bug 的生成器在用 Math.random() 而不是 CSPRNG,或者启动时熵不够,或者某个进程不小心把两个生成器以同样的种子初始化,而不是底层数学。本生成器使用浏览器的 crypto.randomUUID()(可用时)或 crypto.getRandomValues(),二者都从操作系统的 CSPRNG 取熵(Linux 的 getrandom()、Windows 的 BCryptGenRandom、macOS 的 SecRandomCopyBytes),这与 TLS 会话密钥使用的是同一个熵源。
浏览器实现:crypto.randomUUID()
Web Crypto API 把 crypto.randomUUID() 暴露为一个一行调用的生成器,返回一个符合 RFC 4122 的 v4 UUID 字符串。它在 Chrome 92(2021 年 7 月)、Firefox 95(2021 年 12 月)与 Safari 15.4(2022 年 3 月)中交付,大约从 2022 年起在所有现代浏览器中都已是基线可用。对更老的浏览器,标准的回退做法是分配一个 16 字节的 Uint8Array,用 crypto.getRandomValues() 填充,把版本 nibble 设为 4(第 7 个字节高位 nibble = 0x40),把 variant 位设为 10xxxxxx(第 9 个字节最高两位 = 0x80),再把这些字节按 8-4-4-4-12 的十六进制串格式化出来。本生成器在原生存在 crypto.randomUUID() 时使用它,否则使用手工的回退路径,两种路径输出完全相同,只不过回退路径略慢一些。两条路径都完全在你的浏览器里运行;什么都不会经过网络。
用例,以及每一种实际需要的是什么
- 数据库主键,尤其是分布式或分片的系统,在那里协调一个整数计数器并不实际。v7 是现代推荐;若你需要时间戳的不透明性,则用 v4。
- API 请求关联 ID。每个进入的请求都拿到一个 UUID,它会贯穿调用链上的每一个下游服务;任何服务的日志都可以通过这个 ID 追溯回最初的请求。Stripe、Twilio 与 AWS X-Ray 都是这么做的。
- HTTP 请求的幂等键。Stripe 的
Idempotency-Key头接受一个 UUID;如果客户端用同一个键重试同一个请求,Stripe 会返回缓存的响应,而不是给信用卡再扣一次款。这一模式如今在支付 API 之间已是标准。 - 会话令牌,附带注意事项。一个 v4 UUID 是密码学上随机的,有 122 位熵,这对会话 ID 来说绰绰有余。但如果会话令牌仅仅是一个 UUID,那只要任何相关端点把它泄露出去,它就会受到枚举攻击;现代最佳实践是为会话状态使用更长的、签名过的令牌(JWT、Paseto)。
- 用于上传去重的文件名。给每次上传生成一个 UUID,把文件存到
/uploads/{uuid}.ext,你永远不会因为原始文件名而出现命名冲突,也不会因为别人猜中URL 而意外送出别的用户的文件。 - 事件驱动系统中的消息 ID。Kafka、RabbitMQ、AWS SQS 与多数 pub/sub 平台都建议每条消息一个 UUID,用于追踪与去重;由于按时间戳可排序的特性,v7 越来越成为默认选择。
- 测试数据生成。每种语言的 Faker 库都把 UUID 用作生成测试行的默认 ID。
- 分布式系统节点标识符。集群里新启动的节点会给自己生成一个 UUID;集群协调器用这个 ID 来路由流量,以及在日志里识别这个节点。
值得了解的替代方案
UUID 是通用默认,但不是唯一选项,有几种替代方案在特定用例下值得了解。ULID(Universally Unique Lexicographically Sortable Identifier,Alex Knol,约 2016):128 位与 UUID 相同,但用 26 个 Crockford-Base32 字符编码,而不是 32 个十六进制位(更紧凑,而且不区分大小写地 URL-safe。前 48 位是 Unix 毫秒时间戳,所以 ULID 按字典序排序就等于按创建时间排序。在概念上与 UUID v7 非常接近,只是早出现了好几年。Snowflake(Twitter,2010):64 位)比 UUID 小得多,可以装进 SQL BIGINT。41 位时间戳 + 10 位机器 ID + 12 位毫秒内序列。被 Twitter/X、Discord、Instagram 与许多把「64 位主键」当作硬性约束的大规模系统使用。KSUID(Segment,2017):27 个字符,秒级精度时间戳 + 128 位随机。用毫秒精度换更短的字符串表示。nanoid(Andrey Sitnik,2017):一个微小的库,生成长度可配置的 URL-safe 随机标识符。默认 21 个字符,在字节数少很多的同时,提供与 UUID v4 类似的抗碰撞性。对那些原本要在公开 URL 中嵌入 UUID 的场合,nanoid 更短也更友好。代价是:nanoid 标识符并没有把它们标记为 UUID 的「版本+variant」位,所以无法直接接入那些期望 UUID 形状值的系统。
URL 安全与格式变体
UUID 的规范带连字符形式(550e8400-e29b-41d4-a716-446655440000)是 URL-safe 的,每个字符(小写字母、数字、连字符)都在 RFC 3986 定义的未保留集合里。这意味着你可以把一个 UUID 直接放进 URL 的 path 或查询字符串里,不需要做百分号编码。有些系统为了紧凑会去掉连字符,产出一个 32 字符的十六进制串(550e8400e29b41d4a716446655440000),它仍然是 URL-safe 的;由于 UUID 结构是固定的,这种转换是可逆的。少数系统会把 UUID 用大括号包起来({550e8400-e29b-41d4-a716-446655440000}),这是Microsoft 的 GUID 习惯;括号只是装饰,从不会出现在 URL 里。有些系统把十六进制字符大写化;按规范 UUID 是大小写不敏感的,但同一个系统内部保持一致是要紧的。本生成器提供这三个选项(大写、加大括号、不带连字符),以便兼容你正要把 UUID 喂进去的任何流水线。
UUID vs GUID,同一样东西,名字不同
UUID 是 IETF、ISO 与多数开源项目使用的标准术语。GUID(Globally Unique Identifier) 是 Microsoft 在 Windows、.NET、COM/OLE、SQL Server、Active Directory 与 Windows 注册表中使用的术语。两者指的是同样的 128 位标识符、同样的 8-4-4-4-12 十六进制格式。功能上可互换,一个由 Windows 生成的 GUID 可以用在任何期望 UUID 的地方,反之亦然。唯一值得知道的差别:Microsoft 的 GUID 生成在历史上对很多 API 用 UUID v4,但在某些更老的 COM/OLE 上下文中用 UUID v1(带 MAC 地址);这一点在 Microsoft 的 COM 规范中有记载。如果你从一个 Microsoft 来源的系统拿到一个 GUID,想知道它是哪个版本,就检查版本 nibble(第 13 个十六进制字符,v1 是 '1',v4 是 '4',如此类推)。
隐私:为什么仅在浏览器中即便在这里也重要
一个 UUID 本身没有内在意义,那为什么生成器在本地运行还会有意义?两个理由。其一,当 UUID 被用作会话令牌、幂等键或任何其他「类似秘密」的标识符时,在第三方服务器上生成它就意味着那台服务器在你使用之前就已经看到了这个值,一种小但真实的暴露。其二,服务器端那些声称「具有密码学随机性」的生成器,用户没法验证;一台有 bug 或恶意的服务器可能返回看起来随机但其实并不随机的值,而你没办法察觉这种偏差。一个仅在浏览器中运行的生成器,执行的是和你应用在服务器端会执行的完全相同的 crypto.randomUUID() 调用;熵来自同一个操作系统源(Linux 的 getrandom()、Windows 的 BCryptGenRandom、macOS 的 SecRandomCopyBytes);没有任何第三方看到输出。你可以打开 DevTools 的 Network 面板,在点击「生成」时自己确认,根本没有外发请求。让页面在加载完成后离线(飞行模式),生成器仍然能工作。
常见问题
UUID 和 GUID 有什么区别?
它们本质上是同一回事。UUID 是标准术语(RFC 4122),而 GUID(全局唯一标识符)是微软的术语。两者都指采用相同 8-4-4-4-12 十六进制格式的 128-bit 标识符。
两个 UUID 会相同吗?
理论上有可能,但概率极低。UUID v4 有 122 个随机位,可提供约 5.3 × 10³⁶ 种可能值。您需要每秒生成数十亿个 UUID 并持续数十年,才能有 50% 的几率发生一次冲突。
这些 UUID 在加密上安全吗?
是的。本生成器使用 Web Crypto API(crypto.getRandomValues),可提供加密强度的随机值。输出适用于会话令牌等对安全性敏感的用例。
我应该把 UUID v4 还是 v7 用作数据库主键?
如果你的数据库支持,v7 是现代推荐。v4(随机)会插入到 B 树索引中的随机位置,使索引碎片化、把页缓存搅烂。v7(时间戳 + 随机,RFC 9562 2024 年 5 月)会插入到索引最右边,因为 ID 按创建时间排序,和自增整数一样的写性能,同时具有 UUID 的分布与唯一性。Postgres 18+ 内建 uuidv7()。代价是:v7 会泄露每一行的创建时间,这在某些应用里会是隐私顾虑。多数情况下性能收益胜过这点时间戳泄露。
ULID、KSUID 与 nanoid 是什么?
替代的 ID 格式。ULID(Alex Knol,约 2016):像 UUID 一样 128 位,但编码为 26 个 Crockford-Base32 字符;按时间戳字典序排序。KSUID(Segment,2017):27 字符,秒级精度时间戳 + 128 位随机。nanoid(Andrey Sitnik,2017):一个微小的库,生成长度可配的 URL-safe 随机 ID;默认 21 字符在更少字节中提供与 UUID v4 类似的抗碰撞性。Snowflake(Twitter,2010):64 位的 ID,可装进 SQL BIGINT,被 Twitter、Discord 与 Instagram 使用。当接收方系统期望 UUID 格式时用 UUID;当你对大小、可排序性或 URL 友好性有特定要求时,用上述替代方案。
这些 UUID 会被发到任何地方吗?
不会。每个 UUID 都通过 Web Crypto API 在你的浏览器中本地生成。生成器从不发起网络请求,可以在你点击「生成」的同时打开 DevTools 的 Network 面板自行验证,或在页面加载后让它离线、确认工具仍然能工作。这对生成会话令牌、幂等键或其他你不希望任何第三方在你使用之前先看到值的标识符,都是安全的。