Golang雪花算法ID生成器

想用Golang实现一个分布式雪花算法ID生成器,但不太清楚具体怎么处理时间回拨的问题。大家有什么好的解决方案吗?比如是否需要引入NTP服务器同步,或者有什么成熟的第三方库推荐?另外在高并发场景下如何保证性能?

2 回复

使用Go实现雪花算法ID生成器,通过时间戳、机器ID和序列号生成唯一ID。示例代码:

type Snowflake struct {
    machineID int64
    sequence  int64
    lastTime  int64
}

func (s *Snowflake) Generate() int64 {
    // 实现时间戳、机器ID和序列号的组合
    // 返回64位唯一ID
}

特点:高性能、趋势递增、分布式唯一。注意时钟回拨问题。

更多关于Golang雪花算法ID生成器的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,雪花算法(Snowflake)是一种分布式唯一ID生成算法,生成的ID为64位整数,结构如下:

  • 1位符号位(始终为0)
  • 41位时间戳(毫秒级,可用约69年)
  • 10位工作节点ID(5位数据中心ID + 5位机器ID,最多支持1024个节点)
  • 12位序列号(每毫秒可生成4096个ID)

以下是完整的Go实现代码:

package main

import (
	"errors"
	"sync"
	"time"
)

// Snowflake 结构体
type Snowflake struct {
	mu            sync.Mutex
	lastTimestamp int64
	workerID      int64
	datacenterID  int64
	sequence      int64
}

// 定义常量
const (
	workerIDBits     = 5
	datacenterIDBits = 5
	sequenceBits     = 12

	maxWorkerID     = -1 ^ (-1 << workerIDBits)
	maxDatacenterID = -1 ^ (-1 << datacenterIDBits)
	maxSequence     = -1 ^ (-1 << sequenceBits)

	timeShift      = workerIDBits + datacenterIDBits + sequenceBits
	workerShift    = datacenterIDBits + sequenceBits
	datacenterShift = sequenceBits
)

// NewSnowflake 初始化雪花算法生成器
func NewSnowflake(workerID, datacenterID int64) (*Snowflake, error) {
	if workerID < 0 || workerID > maxWorkerID {
		return nil, errors.New("worker ID out of range")
	}
	if datacenterID < 0 || datacenterID > maxDatacenterID {
		return nil, errors.New("datacenter ID out of range")
	}
	return &Snowflake{
		lastTimestamp: -1,
		workerID:      workerID,
		datacenterID:  datacenterID,
		sequence:      0,
	}, nil
}

// NextID 生成下一个ID
func (s *Snowflake) NextID() (int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	timestamp := time.Now().UnixMilli()

	if timestamp < s.lastTimestamp {
		return 0, errors.New("clock moved backwards")
	}

	if timestamp == s.lastTimestamp {
		s.sequence = (s.sequence + 1) & maxSequence
		if s.sequence == 0 {
			for timestamp <= s.lastTimestamp {
				timestamp = time.Now().UnixMilli()
			}
		}
	} else {
		s.sequence = 0
	}

	s.lastTimestamp = timestamp

	return (timestamp << timeShift) |
		(s.workerID << workerShift) |
		(s.datacenterID << datacenterShift) |
		s.sequence, nil
}

// 使用示例
func main() {
	// 初始化生成器(workerID: 1, datacenterID: 1)
	sf, err := NewSnowflake(1, 1)
	if err != nil {
		panic(err)
	}

	// 生成10个ID
	for i := 0; i < 10; i++ {
		id, err := sf.NextID()
		if err != nil {
			panic(err)
		}
		println(id)
	}
}

关键特性:

  1. 线程安全:使用互斥锁(sync.Mutex)保证并发安全
  2. 时钟回拨处理:检测系统时间回退并返回错误
  3. 高性能:每毫秒可生成最多4096个ID
  4. 可配置:支持自定义工作节点和数据中心ID

使用注意事项:

  • 确保工作节点ID和数据中心ID在分布式环境中唯一
  • 系统时钟不能频繁回拨,否则会影响ID生成
  • 41位时间戳从1970-01-01开始,可用到2039年左右

这个实现适合在分布式系统中生成趋势递增的唯一ID,如订单号、用户ID等场景。

回到顶部