告別雪花算法?一文看懂新一代分布式 ID 方案:ULID
從雪花算法到ULID的轉(zhuǎn)變
在構(gòu)建一個 URL 探測系統(tǒng)的過程中,我們對唯一標(biāo)識符生成方式提出了更高的要求:既需要全局唯一,又希望按時間有序,還要足夠高效、分布式友好。傳統(tǒng)的 Snowflake 雖然滿足了時間排序,但受限于中心協(xié)調(diào)器設(shè)計;而 UUID 又缺乏排序性,導(dǎo)致在數(shù)據(jù)庫等場景中效率低下。
這時,我們發(fā)現(xiàn)了 ULID —— 一種新型的分布式唯一標(biāo)識符格式。它結(jié)合了 Snowflake 的時間排序能力與 UUID 的唯一性,甚至在編碼與存儲效率上也勝出一籌。
ULID 是什么?
ULID 全稱為 Universally Unique Lexicographically Sortable Identifier(全局唯一、按字典序可排序的標(biāo)識符),它是一種設(shè)計精妙、實現(xiàn)高效的 128 位標(biāo)識符結(jié)構(gòu):
ULID = 時間戳(48位) + 隨機數(shù)(80位)其最終通過 Base32(Crockford 編碼)編碼后,轉(zhuǎn)化為一個26字符的可讀字符串。
ULID 的核心特性解讀
時間排序性內(nèi)置
ULID 的前 48 位記錄的是毫秒級時間戳,使其在生成時天然按照時間排序。這在下列場景中至關(guān)重要:
- 日志追蹤(日志ID按時間排序)
- 事件溯源系統(tǒng)
- 時序型主鍵設(shè)計(例如:IoT、傳感器數(shù)據(jù))
強唯一性保障
后 80 位使用密碼學(xué)安全隨機數(shù)生成機制,即便在同一毫秒內(nèi)生成大量 ULID,也能保證幾乎無沖突(概率小于 1/(2^80))。相比 UUID v4,ULID 提供了更穩(wěn)妥的隨機性保障。
天然支持分布式
與 Snowflake 不同,ULID 的生成無需中心節(jié)點或協(xié)調(diào)器,可以在任意節(jié)點獨立、安全地產(chǎn)生。非常適合:
- 容器化微服務(wù)
- 云原生環(huán)境
- 無狀態(tài)服務(wù)集群
高性能、無依賴
ULID 的生成過程非常輕量,不依賴網(wǎng)絡(luò)、不涉及鎖競爭,甚至可以嵌入到邊緣設(shè)備中執(zhí)行,滿足低延遲需求。
存儲緊湊、可讀性高
使用 Base32 Crockford 編碼后,ULID 僅需 26 個字符,結(jié)構(gòu)緊湊,比 UUID 更短更易讀,同時也兼容 UUID 的 128 位二進制格式。
ULID 的結(jié)構(gòu)圖解
ULID 內(nèi)部結(jié)構(gòu)如圖:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 32_bit_uint_time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 16_bit_uint_time_low | 16_bit_uint_random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 32_bit_uint_random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 32_bit_uint_random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- 時間部分(48位):表示自 Unix 紀(jì)元以來的毫秒時間戳
- 隨機部分(80位):由高質(zhì)量熵源生成的隨機數(shù)
- 編碼結(jié)果:最終以 26 字符的 Base32 編碼表現(xiàn),天然具備字典序 = 時間順序
ULID 的典型應(yīng)用場景
場景 | 優(yōu)勢 |
分布式系統(tǒng)中的唯一ID | 保證全局唯一性和時間順序,不依賴中心節(jié)點 |
數(shù)據(jù)庫主鍵(尤其是時序庫) | 查詢范圍明確、索引性能高 |
日志跟蹤ID、事務(wù)ID | 保證順序性,便于檢索與追蹤 |
消息隊列中的消息ID | 保證隊列中消息的插入順序 |
在 Golang 中快速上手 ULID
推薦使用 github.com/oklog/ulid 這個成熟庫:
package main
import (
"fmt"
"time"
"github.com/oklog/ulid"
"math/rand"
)
func main() {
// 初始化時間與熵源
t := time.Now()
entropy := rand.New(rand.NewSource(t.UnixNano()))
// 生成 ULID
id := ulid.MustNew(ulid.Timestamp(t), entropy)
// 輸出 ULID
fmt.Println("ULID:", id)
fmt.Println("String:", id.String())
fmt.Println("Time:", ulid.Time(id.Time()))
// 解析 ULID 字符串
if parsed, err := ulid.Parse(id.String()); err == nil {
fmt.Println("Parsed:", parsed)
}
}輸出示例:
ULID: 01HZ9FDZ17GM0CQXD7A71CN48V
String: 01HZ9FDZ17GM0CQXD7A71CN48V
Time: 2025-08-01 09:23:45 +0800 CST
Parsed: 01HZ9FDZ17GM0CQXD7A71CN48V與其他 ID 方案對比一覽
特性 | ULID | UUID v4 | Snowflake |
時間排序性 | 內(nèi)置毫秒時間排序 | 無序 | 有序(需中心協(xié)調(diào)) |
全局唯一性 | 80位隨機數(shù),低沖突 | 高隨機性 | 但易重復(fù) |
分布式支持 | 完全分布式 | 需中心協(xié)調(diào)器 | |
可讀性 | Crockford Base32 編碼 | 不可讀 | 數(shù)字難理解 |
編碼長度 | 26字符 | 36字符 | 18-20位數(shù)值 |
性能 | 快速生成,無依賴 | 涉及機器ID/協(xié)調(diào)邏輯 |
結(jié)語:ULID,是時候換代了
在這個分布式、高并發(fā)成為主流的時代,ID 生成方案不再只是“唯一性”這一維度的考量。我們更關(guān)注:排序性、可讀性、分布式適配能力。
ULID 憑借其毫秒級排序能力、強唯一性、安全隨機性與極高性能,已經(jīng)成為現(xiàn)代系統(tǒng)中替代 UUID 與 Snowflake 的重要候選。
在項目中使用 ULID,你將獲得更清晰的日志、更穩(wěn)定的系統(tǒng)行為、更簡潔的存儲結(jié)構(gòu)。尤其是在 Go 語言生態(tài)中,oklog/ulid 提供了優(yōu)雅且成熟的實現(xiàn),值得每一位后端開發(fā)者嘗試。
是否該告別雪花,迎接新生? 答案,或許在你生成的第一個 ULID 中就已揭曉。






























