编程

ULID vs UUID:为什么 ULID 更适合在分布式系统中使用?

2493 2023-04-15 11:28:00

在分布式系统中,唯一标识符(UUID)是非常常见的,它是用于标识数据或者实体的一种方式,它是基于算法生成的一个固定长度的字符串。然而,UUID 也有一些缺点,例如它们很难被排序,因为它们是随机生成的,这导致了一些性能问题。而 ULID 则是一种新的方案,它解决了这些问题并提供了一些额外的优势。

什么是 ULID?

ULID(Universally Unique Lexicographically Sortable Identifier)是一种可排序、唯一的标识符,由 Alizain Feerasta 在 2016 年提出,它结合了时间戳和随机数生成器来生成一个 32 位的标识符,适用于分布式系统中标识数据实体和事件等场景。

ULID 规范定义了如下的格式:

01AN4Z07BY      79KA1307SR9X4MV3
|----------|    |----------------|
 Timestamp           Randomness
  10 chars           16 chars

其中,Timestamp(时间戳)和 Randomness(随机数)共占 16 个字符,Unique Identifier(唯一标识符)占 16 个字符。ULID 的生成顺序是:时间戳越早的 ULID 排在前面,如果时间戳相同,则随机数越小的 ULID 排在前面。

具体地,Timestamp 部分是由 Unix 时间戳的毫秒数(自 1970年 1 月 1 日以来)进行 base32 编码得到的,占据了前 10 个字符。Randomness 部分是由 CSPRNG(Cryptographically Secure Pseudo-Random Number Generator,密码学安全伪随机数生成器)生成的 6个字节的随机数,进行 base32 编码得到的,占据了接下来的 6 个字符。Unique Identifier 部分是 UUID 的16个字符,用于确保 ULID 的全局唯一性。

下面是一个示例 ULID:

01F9K1BCRK7X6T9GH6AA7YP6GW
Timestamp Randomness Unique Identifier
01F9K1BCRK 7X6T9G H6AA7YP6GW 

如何生成 ULID?

生成 ULID 需要两个部分:时间戳和随机数。时间戳部分占据了 ULID 的前 12 个字符,使用了 UTC 时间,精确到毫秒。随机数部分占据了 ULID 的后 18 个字符,使用了基于 CSPRNG 的随机数生成器。

使用这种生成方式,可以确保生成的 ULID 具有全局唯一性和可排序性。此外,ULID 还使用了基于时间戳的前缀,这使得可以使用前 12 个字符来确定生成 ULID 的时间。这对于调试和数据管理非常有用。

为什么要使用 ULID?

ULID 比 UUID 具有一些优势:

  • 可排序性:由于 ULID 基于时间戳生成,因此可以按照时间戳进行排序,这对于数据库索引和查询非常有用。另外,由于 ULID 采用了基于时间戳的前缀,因此可以使用前 12 个字符来确定时间戳,这使得调试和数据管理更加容易。
  • 可读性:ULID 是由 32 个字符组成的,其中前 12 个字符是由时间戳生成的,可以通过这 12 个字符来确定时间戳。这对于调试和数据管理非常有用。
  • 低碰撞率:ULID 的碰撞率非常低,这是因为它采用了基于时间戳的前缀和随机数生成器生成 ULID,这使得生成的 ULID 在全球范围内都是唯一的。
  • 短且轻量级:ULID 只有 32 个字符,而 UUID 有 36 个字符,这意味着 ULID 更短、更轻量级,更适合在分布式系统中使用。
  • 安全性:ULID 使用了基于 CSPRNG 的随机数生成器来生成随机数部分,这使得它更加安全,不容易受到攻击。

如何在实践中使用 ULID?

如果你想在应用中使用 ULID,你可以使用现有的 ULID 库来生成 ULID。下面是一些流行的 ULID 库:

  • ulid(https://github.com/ulid/spec):这是官方的 ULID 实现库,支持多种编程语言,包括 Go、Java、JavaScript、Python 和 Ruby 等。
  • ulid-js(https://github.com/ulid/javascript):这是 JavaScript 的 ULID 实现库,它支持在浏览器和 Node.js 中使用。
  • rust-ulid(https://github.com/mmacedoeu/rust-ulid):这是 Rust 的 ULID 实现库,它提供了一种安全、高效、易用的方式来生成 ULID。

使用 ULID 的一个例子是在数据库中存储 ULID 作为主键,这将使得数据库中的条目按照时间排序,从而提高了数据库查询的效率。

结论

ULID 是一种比 UUID 更好的方案,它具有可排序性、可读性、低碰撞率、短且轻量级、安全等优势。在分布式系统中,使用 ULID 可以提高数据库查询的效率,同时保证数据的唯一性。如果你正在构建一个分布式系统,不妨考虑使用 ULID 来标识你的数据和实体。