在分布式系统和数据库设计中,“如何生成一个唯一的ID” 一直是个经典话题。我们最熟悉的可能是 UUID,但它也有不少槽点:无法排序、存储占用大、可读性差。今天给大家介绍一个非常有潜力的替代品 —— ULID(Universally Unique Lexicographically Sortable Identifier)。 什么是 ULID? ULID 的全称是 通用唯一词典分类标识符。简单来说,它是一种既能保证全局唯一,又天然支持按时间排序 的标识符。 它的设计目标很明确: 全局唯一:不怕分布式环境下的冲突 时间有序:生成顺序 = 时间顺序 紧凑可读:比 UUID 更短、更友好 ULID 长什么样? 一个标准的 ULID 看起来是这样的: 01H4Z7X8J7F9VYMQK7Z9G9Z9Z9 它是基于 Crockford's Base32 编码的(包含 0–9和 A–Z,去除了 I、L、O、U 以避免混淆),生成的字符串通常统一显示为大写,解码时大小写不敏感。 ULID 的结构 ULID 一共 128 位(16 字节),分为两部分: 部分 长度 作用 时间戳 48 位 Unix 毫秒时间(1970–2088) 随机数 80 位 保证唯一性 ┌─────────────── Timestamp (48 bits) ───────────────┐ ┌───────────────────────────────────────────────────┐ │ Time │ Randomness │ └───────────────────────────────────────────────────┘ 为什么要选 ULID? 1、全局唯一性 ULID 结合了时间 + 随机数,即使在高并发的分布式环境中,碰撞概率也极低。 2、天生支持排序 因为时间戳在最前面,ULID 天然按时间递增。你可以直观地看到,随着时间推移,前面的字符会变大: 01H4Z...(较早) 01H5A...(较晚) 这意味着: 数据库按主键排序 ≈ 按时间排序 不需要额外的时间字段 查询更快,索引更高效 Tip 不要试图在 Windows 11 的资源管理器里按文件名排序来验证 ULID 文件名的时间排序,因为该资源管理器目前只支持自然排序。可以尝试换其他资源管理器或在命令行中列出文件。 3、比 UUID 更紧凑 类型 长度 示例 UUID 36 字符 550e8400-e29b-41d4-a716-446655440000 ULID 26 字符 01H4Z7X8J7F9VYMQK7Z9G9Z9Z9 更短 不含 - 更适合 URL / 文件名 4、高性能 & 去中心化 ULID 的生成: 不需要中心服务器 不需要锁 本地即可生成,非常适合微服务、消息队列、日志系统 5、跨平台支持 主流语言几乎都有成熟实现:Java / Go / Python / Rust / JavaScript。 什么时候不该用 ULID? 虽然 ULID 很香,但并不是万能药。以下场景请慎重考虑: ❌ 需要完全随机且无规律的 ID 如果你的业务要求 ID 不能泄露任何时间信息(例如用于订单号防止被爬虫推测销量),ULID 的前缀时间戳可能会暴露生成频率和时间。这种情况下,UUIDv4 这种完全随机的方案更安全。 ❌ 需要绝对连续且无空洞的 ID ULID 是“趋势递增”,不是“绝对连续”。由于随机部分的存在,它会有空洞。如果你的系统要求 ID 必须严格连续(1, 2, 3...),ULID 不适合。 ❌ 存储空间极度敏感 虽然比 UUID 短,但如果是海量数据且不需要排序,单纯的整型自增 ID(Int/Long)仍然是最省空间的。 ULID 适合用在哪些场景? 日志系统 按时间生成、天然有序,非常适合做日志追踪 ID。 分布式系统 不依赖数据库自增 ID,避免单点瓶颈。 数据库主键 B+Tree 索引友好,写入性能更好。 消息队列 消息 ID 自带时间顺序,消费端更容易处理。 总结 ULID 是一个兼顾“唯一性、时间排序、紧凑性”的现代分布式 ID 方案。如果你正在寻找一个比 UUID 更优雅、比雪花算法更简单的方案,不妨试试 ULI...