idgen

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 13, 2026 License: MIT Imports: 11 Imported by: 0

README

idgen - Genesis ID 生成组件

Go Reference

idgen 是 Genesis 业务层的核心组件,提供高性能的分布式 ID 生成能力。

特性

  • 统一 API 设计:所有组件遵循 New(cfg, opts...) 模式
  • 接口优先:返回接口类型,便于测试和替换实现
  • 后端可插拔:通过 cfg.Driver 选择后端实现(Redis/Etcd)
  • 安全健壮
    • Redis 实现使用 Lua 脚本保证原子性
    • Etcd 实现使用 Txn + Lease 机制,原生支持租约保活
    • 严格的 WorkerID 位宽校验,防止 ID 冲突
    • 时钟回拨保护

快速开始

import "github.com/ceyewan/genesis/idgen"
1. UUID (最简单)
// 生成 UUID v7 (时间排序,适合数据库主键)
id := idgen.UUID()
2. Snowflake (手动指定 WorkerID)
// 创建 Snowflake 生成器
gen, err := idgen.NewGenerator(&idgen.GeneratorConfig{
    WorkerID:     1,  // [0, 1023]
    DatacenterID: 0,  // 可选,[0, 31](启用后 WorkerID 范围变为 [0, 31])
})
if err != nil {
    panic(err)
}

id := gen.Next()       // int64
idStr := gen.NextString() // string
3. Snowflake (Allocator 自动分配 WorkerID)
// 创建 Allocator
allocator, err := idgen.NewAllocator(&idgen.AllocatorConfig{
    Driver:    "redis",
    KeyPrefix: "myapp:worker",
    MaxID:     512,  // [0, 512)
    TTL:       30,   // 租约 TTL 30 秒
}, idgen.WithRedisConnector(redisConn))
if err != nil {
    panic(err)
}

// 分配 WorkerID
workerID, err := allocator.Allocate(ctx)
if err != nil {
    panic(err)
}

// 启动保活 (在 goroutine 中运行)
go func() {
    if err := <-allocator.KeepAlive(ctx); err != nil {
        log.Fatal("WorkerID 租约丢失,停止服务")
    }
}()

// 优雅退出时释放
defer allocator.Stop()

// 使用分配的 WorkerID 创建 Snowflake
gen, err := idgen.NewGenerator(&idgen.GeneratorConfig{WorkerID: workerID})
4. Allocator (Etcd)

Etcd 使用原生的 Txn + Lease 机制,性能优于 Redis Lua 方案:

// 创建 Etcd Allocator
allocator, err := idgen.NewAllocator(&idgen.AllocatorConfig{
    Driver:    "etcd",
    KeyPrefix: "myapp:worker",
    MaxID:     512,
    TTL:       30,
}, idgen.WithEtcdConnector(etcdConn))

workerID, err := allocator.Allocate(ctx)
// ... 用法与 Redis 相同

对比:

特性 Redis (Lua) Etcd (Txn + Lease)
原子性 Lua 脚本 MVCC 事务
保活 后台 goroutine + EXPIRE 原生 KeepAlive
释放 DEL Lease revoke
性能 需脚本加载 原生操作
5. Sequencer (分布式序列号)

基于 Redis/Etcd 的原子递增序列号,支持步长、TTL 和最大值循环。

// 创建 Sequencer (Redis)
seq, err := idgen.NewSequencer(&idgen.SequencerConfig{
    Driver:    "redis",
    KeyPrefix: "order:seq",
    Step:      1,
    TTL:       86400, // 24 小时过期(秒)
}, idgen.WithRedisConnector(redisConn))
if err != nil {
    panic(err)
}

// 获取序列号 (支持动态 Key)
id, err := seq.Next(ctx, "20231224") // Redis Key: order:seq:20231224

// 批量获取
ids, err := seq.NextBatch(ctx, "batch:1", 10)

// 设置初始值(IM 系统迁移历史消息时很有用)
ok, err := seq.SetIfNotExists(ctx, "conversation:1", 1000)

API 参考

UUID
函数 说明
idgen.UUID() 生成 UUID v7 字符串(时间排序)
Generator (Snowflake)
方法 说明
idgen.NewGenerator(cfg, opts...) 创建 Snowflake 生成器(返回 Generator 接口)
gen.Next() 获取下一个 ID (int64)
gen.NextString() 获取下一个 ID (string)

GeneratorConfig:

  • WorkerID: 工作节点 ID [0, 1023](使用 DatacenterID 时范围缩减为 [0, 31])
  • DatacenterID: 数据中心 ID [0, 31],可选
Allocator (WorkerID 分配器)
方法 说明
idgen.NewAllocator(cfg, opts...) 创建分配器(支持 Redis/Etcd)
allocator.Allocate(ctx) 分配 WorkerID
allocator.KeepAlive(ctx) 保持租约(返回 <-chan error)
allocator.Stop() 释放资源

AllocatorConfig:

  • Driver: 后端类型,"redis" 或 "etcd"
  • KeyPrefix: 键前缀,默认 "genesis:idgen:worker"
  • MaxID: 最大 ID 范围 [0, maxID),默认 1024
  • TTL: 租约 TTL(秒),默认 30
Sequencer (序列号生成器)
方法 说明
idgen.NewSequencer(cfg, opts...) 创建序列号生成器(支持 Redis/Etcd)
seq.Next(ctx, key) 获取下一个序列号
seq.NextBatch(ctx, key, count) 批量获取序列号
seq.Set(ctx, key, value) 设置序列号值
seq.SetIfNotExists(ctx, key, value) 仅当不存在时设置

SequencerConfig:

  • Driver: 后端类型,"redis" 或 "etcd",默认 "redis"
  • KeyPrefix: 键前缀
  • Step: 步长,默认 1
  • MaxValue: 最大值(0 表示不限制)
  • TTL: 过期时间(秒),0 表示永不过期
选项函数

所有组件支持统一的选项注入:

选项 说明
idgen.WithLogger(logger) 设置 Logger
idgen.WithRedisConnector(conn) 注入 Redis 连接器
idgen.WithEtcdConnector(conn) 注入 Etcd 连接器

最佳实践

  1. WorkerID 管理:

    • K8s StatefulSet: 直接使用 Pod 序号作为 WorkerID
    • 无状态 Deployment: 使用 Allocator 自动分配
  2. Allocator 保活监控:

    go func() {
        if err := <-allocator.KeepAlive(ctx); err != nil {
            // 租约丢失,停止服务以避免 ID 冲突
            log.Fatal("WorkerID lease lost")
        }
    }()
    
  3. IM 系统序列号初始化:

    // 迁移历史消息后,初始化 seq_id
    ok, _ := seq.SetIfNotExists(ctx, "conversation:1", maxHistorySeqID)
    
  4. 优雅退出:

    defer allocator.Stop()  // 释放 WorkerID
    

Documentation

Overview

Package idgen 提供高性能的 ID 生成能力,支持多种 ID 生成策略:

  • Generator: 基于雪花算法的分布式有序 ID 生成接口
  • UUID: UUID v7 生成(时间排序,适合数据库主键)
  • Sequencer: 基于 Redis/Etcd 的分布式序列号生成器接口
  • Allocator: 支持 Redis/Etcd 的 WorkerID 自动分配器

设计原则:

  • 配置驱动: 统一使用 New(cfg, opts...) 模式
  • 接口优先: 面向接口编程,便于切换底层实现
  • 高性能: 优化热路径,无锁或低锁竞争
  • 实例优先: 支持多实例共存

基本使用:

// Generator (Snowflake)
gen, _ := idgen.NewGenerator(&idgen.GeneratorConfig{WorkerID: 1})
id := gen.Next()

// UUID
uid := idgen.UUID()

// Sequencer
seq, _ := idgen.NewSequencer(&idgen.SequencerConfig{
    KeyPrefix: "order:",
    Step:      1,
}, idgen.WithRedisConnector(redisConn))
nextID, _ := seq.Next(ctx, "user:1")

// Allocator (自动分配 WorkerID)
allocator, _ := idgen.NewAllocator(&idgen.AllocatorConfig{
    Driver: "redis",
    MaxID:  512,
}, idgen.WithRedisConnector(redisConn))
workerID, _ := allocator.Allocate(ctx)
defer allocator.Stop()
go func() { if err := <-allocator.KeepAlive(ctx); err != nil { ... } }()

Index

Constants

View Source
const (
	// MetricSnowflakeGenerated 雪花算法 ID 生成总数 (Counter)
	MetricSnowflakeGenerated = "idgen_snowflake_generated_total"

	// MetricSequenceGenerated 序列号生成总数 (Counter)
	MetricSequenceGenerated = "idgen_sequence_generated_total"
)

Metrics 指标常量定义

Variables

View Source
var (
	// ErrConnectorNil 连接器为空
	ErrConnectorNil = xerrors.New("idgen: connector is nil")

	// ErrWorkerIDExhausted WorkerID 已耗尽
	ErrWorkerIDExhausted = xerrors.New("idgen: no available worker id")

	// ErrClockBackwards 时钟回拨超过限制
	ErrClockBackwards = xerrors.New("idgen: clock moved backwards too much")

	// ErrInvalidInput 无效的输入
	ErrInvalidInput = xerrors.New("idgen: invalid input")

	// ErrLeaseExpired Etcd Lease 已过期
	ErrLeaseExpired = xerrors.New("idgen: lease expired")
)

Functions

func ParseGeneratorID

func ParseGeneratorID(id int64) (timestamp, datacenterID, workerID, sequence int64)

ParseGeneratorID 解析 Snowflake ID,返回其组成部分

func UUID

func UUID() string

UUID 生成 UUID v7 字符串(时间排序,适合数据库主键)

使用示例:

id := idgen.UUID()

Types

type Allocator

type Allocator interface {
	// Allocate 分配 WorkerID(阻塞直到分配成功)
	Allocate(ctx context.Context) (int64, error)

	// KeepAlive 保持租约(阻塞方法,应在 goroutine 中运行)
	// 返回错误通道,保活失败时会发送错误
	KeepAlive(ctx context.Context) <-chan error

	// Stop 停止保活并释放资源
	Stop()
}

Allocator WorkerID 分配器接口 用于在集群环境中自动分配唯一的 WorkerID,避免手动配置冲突

func NewAllocator

func NewAllocator(cfg *AllocatorConfig, opts ...Option) (Allocator, error)

NewAllocator 创建 WorkerID 分配器 根据 cfg.Driver 选择 redis 或 etcd 实现

使用示例:

// Redis 分配器
allocator, _ := idgen.NewAllocator(&idgen.AllocatorConfig{
    Driver: "redis",
    MaxID:  512,
}, idgen.WithRedisConnector(redisConn))

workerID, _ := allocator.Allocate(ctx)
defer allocator.Stop()

go func() {
    if err := <-allocator.KeepAlive(ctx); err != nil {
        // 处理保活失败
    }
}()

type AllocatorConfig

type AllocatorConfig struct {
	// Driver 后端类型: "redis" | "etcd"
	Driver string `yaml:"driver" json:"driver"`

	// KeyPrefix 键前缀,默认 "genesis:idgen:worker"
	KeyPrefix string `yaml:"key_prefix" json:"key_prefix"`

	// MaxID 最大 ID 范围 [0, maxID),默认 1024
	MaxID int `yaml:"max_id" json:"max_id"`

	// TTL 租约 TTL(秒),默认 30
	TTL int `yaml:"ttl" json:"ttl"`
}

AllocatorConfig WorkerID 分配器配置

type Generator

type Generator interface {
	// Next 生成下一个 ID
	Next() int64

	// NextString 生成下一个 ID (字符串形式)
	NextString() string
}

Generator ID 生成器接口 提供高性能的分布式 ID 生成能力

func NewGenerator

func NewGenerator(cfg *GeneratorConfig, opts ...Option) (Generator, error)

NewGenerator 创建 ID 生成器 (Snowflake 实现)

使用示例:

gen, _ := idgen.NewGenerator(&idgen.GeneratorConfig{WorkerID: 1})
id := gen.Next()

type GeneratorConfig

type GeneratorConfig struct {
	// WorkerID 工作节点 ID [0, 1023]
	WorkerID int64 `yaml:"worker_id" json:"worker_id"`

	// DatacenterID 数据中心 ID [0, 31],可选
	DatacenterID int64 `yaml:"datacenter_id" json:"datacenter_id"`
}

GeneratorConfig ID 生成器配置 (Snowflake)

type Option

type Option func(*options)

Option 组件初始化选项函数

func WithEtcdConnector

func WithEtcdConnector(conn connector.EtcdConnector) Option

WithEtcdConnector 注入 Etcd 连接器 目前仅用于 Allocator 组件

func WithLogger

func WithLogger(logger clog.Logger) Option

WithLogger 设置 Logger

func WithMeter

func WithMeter(m metrics.Meter) Option

WithMeter 注入指标 Meter(默认使用 metrics.Discard)

func WithRedisConnector

func WithRedisConnector(conn connector.RedisConnector) Option

WithRedisConnector 注入 Redis 连接器 用于 Allocator、Sequencer 等组件

type Sequencer

type Sequencer interface {
	// Next 为指定键生成下一个序列号
	Next(ctx context.Context, key string) (int64, error)

	// NextBatch 为指定键批量生成序列号
	NextBatch(ctx context.Context, key string, count int) ([]int64, error)

	// Set 直接设置序列号的值
	// 警告:此操作会覆盖现有值,请谨慎使用
	Set(ctx context.Context, key string, value int64) error

	// SetIfNotExists 仅当键不存在时设置序列号的值
	// 返回 true 表示设置成功,false 表示键已存在
	SetIfNotExists(ctx context.Context, key string, value int64) (bool, error)
}

Sequencer 序列号生成器接口 提供基于 Redis/Etcd 的分布式序列号生成能力

func NewSequencer

func NewSequencer(cfg *SequencerConfig, opts ...Option) (Sequencer, error)

NewSequencer 创建序列号生成器(配置驱动,目前仅支持 Redis)

使用示例:

seq, _ := idgen.NewSequencer(&idgen.SequencerConfig{
    KeyPrefix: "im:seq",
    Step:      1,
    TTL:       3600, // 1 hour (秒)
}, idgen.WithRedisConnector(redisConn))

// IM 场景使用
id, _ := seq.Next(ctx, "alice")  // Alice 的消息序号
id, _ := seq.Next(ctx, "bob")    // Bob 的消息序号

type SequencerConfig

type SequencerConfig struct {
	// Driver 后端类型: "redis" | "etcd",默认 "redis"
	Driver string `yaml:"driver" json:"driver"`

	// KeyPrefix 键前缀
	KeyPrefix string `yaml:"key_prefix" json:"key_prefix"`

	// Step 步长,默认为 1
	Step int64 `yaml:"step" json:"step"`

	// MaxValue 最大值限制,达到后循环(0 表示不限制)
	MaxValue int64 `yaml:"max_value" json:"max_value"`

	// TTL 键过期时间(秒),0 表示永不过期
	TTL int64 `yaml:"ttl" json:"ttl"`
}

SequencerConfig 序列号生成器配置

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL