golang实现通用唯一词典排序标识符ULID的插件库ulid的使用

Golang实现通用唯一词典排序标识符ULID的插件库ulid的使用

ULID(Universally Unique Lexicographically Sortable Identifier)是一种通用唯一词典排序标识符,相比UUID有以下优势:

ULID的优势

  • 兼容UUID/GUID
  • 每毫秒可生成1.21e+24个唯一ULID
  • 可词典排序
  • 使用26个字符编码(UUID为36个)
  • 使用Crockford的base32编码,效率更高且更易读
  • 大小写不敏感
  • 无特殊字符(URL安全)
  • 单调排序顺序(正确处理同一毫秒内的生成)

安装

使用Go模块安装:

go get github.com/oklog/ulid/v2

基本使用

简单生成ULID

package main

import (
	"fmt"
	"github.com/oklog/ulid/v2"
)

func main() {
	// 最简单的方式生成ULID
	fmt.Println(ulid.Make())
	// 输出示例: 01G65Z755AFWAKHE12NY0CQ9FH
}

高级用法

package main

import (
	"fmt"
	"math/rand"
	"time"
	"github.com/oklog/ulid/v2"
)

func main() {
	// 使用自定义熵源
	entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
	
	// 获取当前时间的毫秒时间戳
	ms := ulid.Timestamp(time.Now())
	
	// 生成ULID
	id := ulid.New(ms, entropy)
	fmt.Println(id)
	// 输出示例: 01G65Z755AFWAKHE12NY0CQ9FH
}

安全考虑

  • 对于安全敏感的场景,应使用crypto/rand作为熵源
  • 对于高性能场景,可以考虑使用sync.Pool来池化熵源

命令行工具

该库还提供了命令行工具:

go install github.com/oklog/ulid/v2/cmd/ulid@latest

使用示例:

$ ulid
01D78XYFJ1PRM1WPBCBT3VHMNV

$ ulid -z
01D78XZ44G0000000000000000

$ ulid 01D78XZ44G0000000000000000
Sun Mar 31 03:51:23.536 UTC 2019

ULID规范

组成部分

  • 时间戳:48位,UNIX毫秒时间戳
  • :80位,用户定义的熵源

编码

使用Crockford的Base32编码,排除了容易混淆的字母I、L、O和U:

0123456789ABCDEFGHJKMNPQRSTVWXYZ

字符串表示

01AN4Z07BY      79KA1307SR9X4MV3
|----------|    |----------------|
 Timestamp           Entropy
  10 chars           16 chars
   48bits             80bits
   base32             base32

性能基准

在Intel Core i7 Ivy Bridge 2.7 GHz,MacOS 10.12.1和Go 1.8.0beta1上的基准测试结果:

BenchmarkNew/WithCryptoEntropy-8      2000000        771 ns/op
BenchmarkNew/WithEntropy-8            20000000      65.8 ns/op
BenchmarkNew/WithoutEntropy-8         50000000      30.0 ns/op
BenchmarkParse-8                      50000000      30.0 ns/op
BenchmarkString-8                     20000000      64.9 ns/op

以上是Golang中使用ulid库生成和处理ULID标识符的基本方法。ULID提供了比UUID更好的排序性能和更紧凑的表示形式,适合需要按时间排序的场景。


更多关于golang实现通用唯一词典排序标识符ULID的插件库ulid的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现通用唯一词典排序标识符ULID的插件库ulid的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 实现 ULID 的插件库使用指南

ULID (Universally Unique Lexicographically Sortable Identifier) 是一种比 UUID 更适合数据库主键的标识符方案,它同时具备:

  1. 按时间排序的特性
  2. 128位的唯一性保证
  3. 比 UUID 更友好的字符串表示形式

安装 ULID 库

go get github.com/oklog/ulid/v2

基本使用示例

package main

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/oklog/ulid/v2"
)

func main() {
	// 1. 生成新的 ULID
	entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
	ms := ulid.Timestamp(time.Now())
	id, err := ulid.New(ms, entropy)
	if err != nil {
		panic(err)
	}
	fmt.Println("Generated ULID:", id)
	
	// 2. 解析字符串为 ULID
	parsed, err := ulid.Parse(id.String())
	if err != nil {
		panic(err)
	}
	fmt.Println("Parsed ULID:", parsed)
	
	// 3. 获取时间部分
	fmt.Println("Time:", ulid.Time(id.Time()))
	
	// 4. 比较两个 ULID
	id2, _ := ulid.New(ulid.Timestamp(time.Now().Add(time.Second)), entropy)
	fmt.Println("Comparison:", id.Compare(id2))
}

高级用法

自定义熵源

func customEntropy() {
	// 使用 crypto/rand 作为更安全的熵源
	entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
	id := ulid.MustNew(ulid.Timestamp(time.Now()), entropy)
	fmt.Println("Secure ULID:", id)
}

批量生成 ULID

func batchGenerate() {
	entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
	now := time.Now()
	
	ids := make([]ulid.ULID, 5)
	for i := range ids {
		ids[i] = ulid.MustNew(ulid.Timestamp(now.Add(time.Duration(i)*time.Millisecond), entropy)
	}
	
	for _, id := range ids {
		fmt.Println(id)
	}
}

数据库集成示例

type User struct {
	ID   ulid.ULID `json:"id" db:"id"`
	Name string    `json:"name" db:"name"`
}

func createUser(name string) User {
	entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
	return User{
		ID:   ulid.MustNew(ulid.Timestamp(time.Now()), entropy),
		Name: name,
	}
}

func dbExample() {
	user := createUser("Alice")
	fmt.Printf("User created: %+v\n", user)
	
	// 模拟数据库存储和查询
	db := make(map[string]User)
	db[user.ID.String()] = user
	
	// 查询
	if u, ok := db[user.ID.String()]; ok {
		fmt.Println("Found user:", u.Name)
	}
}

性能考虑

  1. ULID 生成速度比 UUID v4 稍慢,但比 UUID v1/v2 快
  2. 对于高并发场景,建议使用 ulid.Monotonic 熵源
  3. 字符串表示形式比 UUID 更紧凑(26个字符 vs 36个字符)

适用场景

  1. 数据库主键(特别是需要按时间排序的)
  2. 分布式系统唯一标识
  3. 日志追踪ID
  4. 需要人类可读但又保持唯一性的标识符

ULID 提供了比传统 UUID 更好的排序特性,同时保持了足够的唯一性,非常适合作为现代分布式系统的标识符方案。

回到顶部