一種新的分布式ID生成方案
ULID: 一種新的分布式ID生成方案
ULID (Universally Unique Lexicographically Sortable Identifier) 是一種較新的分布式ID生成方案,旨在解決傳統UUID和雪花算法(Snowflake)的一些局限性。
ULID的主要特點
可排序性:ULID按生成時間嚴格排序,便于數據庫索引優化
128位兼容性:與UUID相同的128位長度(26字符Base32編碼)
無特殊字符:僅使用Base32編碼(字母A-Z和數字2-7)
跨語言支持:多種編程語言實現可用
單調遞增:同一毫秒內生成的ULID也能保持順序
ULID結構
適用場景
需要按時間排序的數據庫主鍵
分布式系統需要無協調的ID生成
需要人類可讀但不想暴露內部信息的ID
替換UUIDv4但需要排序能力的場景
各語言實現示例
javascript
// Node.js
const { ULID } = require('ulid');
const id = ULID(); // 01H5Z7K0G2ABC123DEF456GHJ
Python
import ulid
id = ulid.new() # 01H5Z7K0G2ABC123DEF456GHJ
Java
// Java
import de.huxhorn.sulky.ulid.ULID;
ULID ulid = new ULID();
String id = ulid.nextULID(); // 01H5Z7K0G2ABC123DEF456GHJ
優缺點分析
優點:
無需中心化協調器
比UUID更友好的排序和索引性能
比Snowflake更簡單的實現
時間信息可提取(前10字符代表時間)
缺點:
隨機部分不如UUIDv4隨機(時間部分固定)
相對較新,生態支持不如UUID廣泛
80位隨機性理論上存在沖突可能(但極低)
ULID為分布式系統ID生成提供了一個平衡了排序性、唯一性和易用性的新選擇,特別適合需要時間排序的場景。
1. 添加依賴
首先添加 ULID 的 Java 實現庫到你的項目中:
Maven 依賴
<dependency><groupId>com.github.f4b6a3</groupId><artifactId>ulid-creator</artifactId><version>5.2.0</version> <!-- 檢查最新版本 -->
</dependency>
2. 基本使用方法
import com.github.f4b6a3.ulid.Ulid;
import com.github.f4b6a3.ulid.UlidCreator;public class UlidExample {public static void main(String[] args) {// 生成一個ULIDUlid ulid = UlidCreator.getUlid();System.out.println("ULID: " + ulid); // 例如: 01H5Z7K0G2ABC123DEF456GHJ// 獲取ULID的不同部分System.out.println("Timestamp: " + ulid.getTimestamp()); // 48位時間戳System.out.println("Random: " + ulid.getRandom()); // 80位隨機部分// 獲取字符串表示String ulidString = ulid.toString();System.out.println("String: " + ulidString);// 從字符串解析ULIDUlid parsedUlid = Ulid.from(ulidString);System.out.println("Parsed: " + parsedUlid);}
}
3. 高級用法
單調遞增ULID (同一毫秒內有序)
// 創建單調遞增的ULID生成器
UlidCreator.Monotonic ulidMonotonic = UlidCreator.getMonotonicUlid();
// 同一毫秒內生成的ULID會保持順序
Ulid ulid1 = ulidMonotonic.create();
Ulid ulid2 = ulidMonotonic.create();
System.out.println(ulid1.compareTo(ulid2) < 0); // 輸出 true
自定義隨機數生成器
import java.security.SecureRandom;// 使用更安全的隨機數生成器
SecureRandom secureRandom = new SecureRandom();
Ulid ulid = UlidCreator.getUlid(secureRandom);
獲取時間信息
import java.time.Instant;Ulid ulid = UlidCreator.getUlid();
Instant instant = ulid.getInstant(); // 獲取生成時間
System.out.println("Created at: " + instant);
4. 性能優化
對于高性能場景,可以使用更高效的方法:
// 生成ULID并直接獲取字節數組
byte[] bytes = new byte[16];
UlidCreator.getUlid(bytes); // 填充16字節數組
// 從字節數組創建ULID
Ulid fromBytes = Ulid.from(bytes);
5. 與UUID互轉
import java.util.UUID;
// ULID轉UUID
Ulid ulid = UlidCreator.getUlid();
UUID uuid = ulid.toUuid();
// UUID轉ULID
Ulid fromUuid = Ulid.from(uuid);
6. 完整工具類示例
import com.github.f4b6a3.ulid.Ulid;
import com.github.f4b6a3.ulid.UlidCreator;import java.time.Instant;
import java.util.UUID;public class UlidUtils {/*** 生成標準ULID*/public static String generate() {return UlidCreator.getUlid().toString();}/*** 生成單調遞增ULID*/public static String generateMonotonic() {return UlidCreator.getMonotonicUlid().create().toString();}/*** 獲取ULID的生成時間*/public static Instant getInstant(String ulid) {return Ulid.from(ulid).getInstant();}/*** ULID轉UUID*/public static UUID toUuid(String ulid) {return Ulid.from(ulid).toUuid();}/*** UUID轉ULID*/public static String fromUuid(UUID uuid) {return Ulid.from(uuid).toString();}/*** 驗證字符串是否為有效ULID*/public static boolean isValid(String ulid) {try {Ulid.from(ulid);return true;} catch (IllegalArgumentException e) {return false;}}
}
7. 性能考慮
基準測試:在常規硬件上,ULID生成速度可達每秒數百萬次
線程安全:UlidCreator是線程安全的
無阻塞:實現不依賴網絡或IO操作
8. 注意事項
ULID區分大小寫,但標準實現通常使用大寫字母
時間戳部分基于UNIX時間戳(毫秒),可表示到10889年
隨機部分使用安全的隨機數生成器
在極高并發(同一毫秒內超過2^80次生成)時理論上可能沖突,但實際幾乎不可能