ULID:一种更友好的唯一标识符
大约 2 分钟
ULID:一种更友好的唯一标识符
一、什么是 ULID ?
ULID(Universally Unique Lexicographically Sortable Identifier)是一种结合了时间戳和随机数的全局唯一标识符方案。
相比传统的 UUID 的优势
- 可排序性: ULID 按时间顺序生成,可以方便地按时间排序。
- 可读性: ULID 使用 Crockford's Base32 编码,比 UUID 的十六进制表示更易于阅读和记忆。
- 唯一性: ULID 包含 48 位时间戳和 80 位随机数,保证了极高的唯一性。
- 跨平台: ULID 的生成算法简单,易于在各种编程语言中实现。
ULID 凭借其天然的排序特性和良好的兼容性,正在成为现代应用开发中的优选 ID 方案。非常适合需要跨平台协作的项目。
二、ULID 结构解析
ULID 是一个 26 个字符的字符串,由以下部分组成:
- 时间戳 (10 个字符): 48 位整数,表示从 1970-01-01 00:00:00 UTC 开始的毫秒数。
- 随机数 (16 个字符): 80 位随机数,保证唯一性。
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
时间戳(48位) 随机数(80位)
三、 各语言生成实践
Go 语言
package main
import (
"math/rand"
"time"
"github.com/oklog/ulid/v2"
)
func main() {
entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
ms := ulid.Timestamp(time.Now())
id, _ := ulid.New(ms, entropy)
println(id.String()) // 01H5ZJQJG8P6S3QW4K4M7W0R2G
}
Python
import ulid
new_id = ulid.new()
print(str(new_id)) # 01H5ZJQJGHFN4MDVP3W5B0J6CX
PHP
<?php
use Ulid\Ulid;
require 'vendor/autoload.php';
// 生成新ULID
$ulid = Ulid::generate();
echo $ulid; // 01H5ZJQJGG3ZJ5M6KJ7Q8K9W0R
// 带时间戳生成
$timestamp = (int) (microtime(true) * 1000);
$ulid = Ulid::generate($timestamp);
Java
import de.huxhorn.sulky.ulid.ULID;
public class Main {
public static void main(String[] args) {
ULID ulid = new ULID();
String id = ulid.nextULID();
System.out.println(id); // 01H5ZJQJGH61ZR5T6X7P8Q9W0E
}
}
四、关键特性对比
| ULID | UUID | |
|---|---|---|
| 可排序性 | ✅按时间戳 | ❌ 随机 |
| 可读性 | ✅ Base32 | ❌ 十六进制 |
| 长度 | 26字符 | 36字符 |
| 冲突概率 | 1e-21 | 1e-15 |
五、应用场景
- 数据库主键(特别适合时序数据)
- 分布式系统事件ID
- 日志追踪标识符
- 需要时间排序的目录结构
六、注意事项
- 时间戳精度为毫秒级
- 不建议用于密码学安全场景
- 推荐结合 Monotonic Entropy 提高并发安全性