Skip to content
Go back

分布式 ID 对比

Updated:
Edit

以 Go 为例对比当前常用的 ID 生成方案。与 Snowflake 同类的 Leaf、UidGenerator、TinyId 等未单独列出。

字段说明

维度含义
二进制位长原始位数,决定唯一空间
文本长度编码后字符串长度,影响存储与索引
有序性是否时间可排序,影响 DB 索引局部性
安全性是否密码学安全随机,能否被预测
时间嵌入是否含时间戳,便于按时间范围查
分布式友好是否无需中心节点 / 机器 ID 分配

有序性细分:严格递增(同毫秒内靠序列号,如 Snowflake);趋势递增(时间部分有序,同毫秒内随机,如 UUIDv7)。

方案对比

方案二进制位长文本长度有序性安全性时间嵌入分布式友好主要优点主要缺点
Snowflake6419 数字严格递增否(需机器 ID)高性能、索引友好时钟同步、机器 ID 管理
Sonyflake6419 数字严格递增否(需机器 ID)改进回拨处理生态小于 Snowflake
UUIDv412836 字符无序无协调、标准存储大、索引差
UUIDv712836 字符趋势递增IETF 标准、时间有序文本仍较长
ShortUUID12822 字符无序压缩 UUID仍无序
NanoID12621 字符无序短、生成快无序,不适合时序
ULID12826 字符趋势递增Base32、可排序毫秒精度,极高并发需注意
KSUID16027 字符趋势递增秒级时间 + Base62位长偏大
XID9624 字符趋势递增MongoDB 生态、快随机性弱于 UUID
Sqids可变<10 字符无序极短、人类可读非全局唯一,需上下文

安全性:高 = Crypto API;中 = 混合随机源;低 = Math.random() 类。

推荐

测试代码

package main

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

	"github.com/bwmarrin/snowflake"
	"github.com/gofrs/uuid"
	"github.com/jaevor/go-nanoid"
	"github.com/lithammer/shortuuid/v4"
	"github.com/oklog/ulid"
	"github.com/rs/xid"
	"github.com/segmentio/ksuid"
	"github.com/sony/sonyflake"
	"github.com/sqids/sqids-go"
)

func main() {
	snowflakeTest()
	sonyflakeTest()
	uuidV4Test()
	uuidV7Test()
	shortuuidTest()
	nanoidTest()
	ulidTest()
	xidTest()
	ksuidTest()
	sqidsTest()
}

func snowflakeTest() {
	n, _ := snowflake.NewNode(1)
	id := n.Generate().String()
	fmt.Println("snowflake:", id, "length:", len(id))
}

func sonyflakeTest() {
	t := time.Now()
	s := sonyflake.NewSonyflake(sonyflake.Settings{
		StartTime: t,
		MachineID: func() (uint16, error) { return 1, nil },
		CheckMachineID: func(u uint16) bool { return true },
	})
	id, _ := s.NextID()
	fmt.Println("sonyflake:", id, "length:", len(strconv.FormatUint(id, 10)))
}

func uuidV4Test() {
	id, _ := uuid.NewV4()
	fmt.Println("uuid v4:", id.String(), "length:", len(id.String()))
}

func uuidV7Test() {
	// 需 github.com/gofrs/uuid v5.4+
	id, _ := uuid.NewV7()
	fmt.Println("uuid v7:", id.String(), "length:", len(id.String()))
}

func shortuuidTest() {
	id := shortuuid.New()
	fmt.Println("shortUUID:", id, "length:", len(id))
	a := "12345#$%^&*67890qwerty/;'~!@uiopasdfghjklzxcvbnm,.()_+·><"
	id = shortuuid.NewWithAlphabet(a)
	fmt.Println("shortUuid2:", id, "length:", len(id))
}

func nanoidTest() {
	s, _ := nanoid.Standard(21)
	id := s()
	fmt.Println("nanoid:", id, "length:", len(id))
	c, _ := nanoid.CustomASCII("0123456789", 12)
	id = c()
	fmt.Println("nanoid2:", id, "length:", len(id))
}

func ulidTest() {
	t := time.Now().UTC()
	e := rand.New(rand.NewSource(t.UnixNano()))
	id := ulid.MustNew(ulid.Timestamp(t), e)
	fmt.Println("ulid:", id.String(), "length:", len(id.String()))
}

func xidTest() {
	id := xid.New()
	fmt.Println("xid:", id, "length:", len(id))
}

func ksuidTest() {
	id := ksuid.New()
	fmt.Println("ksuid:", id, "length:", len(id))
}

func sqidsTest() {
	s, _ := sqids.New()
	id, _ := s.Encode([]uint64{1, 2, 3})
	fmt.Println("sqids:", id, "length:", len(id))
	s, _ = sqids.New(sqids.Options{
		MinLength: 10,
	})
	id, _ = s.Encode([]uint64{1, 2, 3})
	fmt.Println("sqids2:", id, "length:", len(id))
	numbers := s.Decode(id)
	fmt.Println("sqids numbers:", numbers)
}

Edit
Share this post on:

Previous Post
游戏引擎和服务端框架对比
Next Post
VS Code 配置