golang,go,博客,开源,编程
雪花算法(Snowflake Algorithm)在 Go 语言中的实现,基本的思路和原理与其他语言相同,依然是将 64 位整型(int64
)划分为几个部分,分别表示时间戳、机器 ID、数据中心 ID 和序列号等信息。以下是一个完整的 Go 语言实现雪花算法的例子。
package main
import (
"fmt"
"sync"
"time"
)
const (
// 初始时间戳:自定义的纪元时间(通常设置为某个固定的起始时间)
epoch int64 = 1609459200000 // 2021年1月1日 00:00:00的毫秒级时间戳
workerBits uint8 = 10 // 机器 ID 的位数
sequenceBits uint8 = 12 // 序列号的位数
workerMax int64 = -1 ^ (-1 << workerBits) // 最大机器 ID (1023)
sequenceMask int64 = -1 ^ (-1 << sequenceBits) // 最大序列号 (4095)
workerShift uint8 = sequenceBits // 机器 ID 的位移量
timestampShift uint8 = workerBits + workerShift // 时间戳的位移量
)
// Snowflake 结构体,包含了当前机器的 ID 和生成 ID 所需要的状态
type Snowflake struct {
mu sync.Mutex
lastTimestamp int64 // 上次生成 ID 时的时间戳
workerID int64 // 当前机器的 ID
sequence int64 // 当前毫秒内的序列号
}
// NewSnowflake 创建一个新的 Snowflake 实例
func NewSnowflake(workerID int64) (*Snowflake, error) {
if workerID < 0 || workerID > workerMax {
return nil, fmt.Errorf("worker ID should be between 0 and %d", workerMax)
}
return &Snowflake{
workerID: workerID,
}, nil
}
// generateID 生成一个唯一的雪花 ID
func (s *Snowflake) generateID() int64 {
s.mu.Lock() // 保证线程安全
defer s.mu.Unlock()
// 获取当前时间戳(单位:毫秒)
timestamp := time.Now().UnixMilli() - epoch
// 如果当前时间戳和上次生成 ID 的时间戳相同,递增序列号
if timestamp == s.lastTimestamp {
s.sequence = (s.sequence + 1) & sequenceMask
// 如果序列号已经达到最大值,等待下一毫秒
if s.sequence == 0 {
for timestamp <= s.lastTimestamp {
timestamp = time.Now().UnixMilli() - epoch
}
}
} else {
// 不同时间戳,重置序列号
s.sequence = 0
}
s.lastTimestamp = timestamp
// 根据雪花算法的位分配生成最终的 ID
id := (timestamp << timestampShift) |
(s.workerID << workerShift) |
s.sequence
return id
}
func main() {
// 创建一个 Snowflake 实例,指定机器 ID(这里为1)
sf, err := NewSnowflake(1)
if err != nil {
fmt.Println("Error:", err)
return
}
// 生成并打印多个 ID
for i := 0; i < 10; i++ {
id := sf.generateID()
fmt.Printf("Generated ID: %d\n", id)
}
}
epoch
: 自定义的纪元时间(起始时间),通常是某个固定的时间戳。这里选择了 2021 年 1 月 1 日 00:00:00 的毫秒级时间戳。workerBits
: 机器 ID 所占的位数。通过调整该值可以改变集群中可支持的机器数量(例如,workerBits
为 10 时,最多支持 1024 台机器)。sequenceBits
: 序列号的位数,决定了每个机器在同一毫秒内可以生成多少个唯一的 ID(例如,sequenceBits
为 12 时,最多支持每毫秒生成 4096 个 ID)。Snowflake
:
workerID
: 当前机器的 ID,用于区分不同机器生成的 ID。sequence
: 当前毫秒内生成的 ID 序列号,从 0 开始递增,最多为 4095。lastTimestamp
: 记录上一次生成 ID 时的时间戳,确保在同一毫秒内生成不同的 ID。generateID
方法:
timestamp << timestampShift
: 时间戳左移后的值。s.workerID << workerShift
: 机器 ID 左移后的值。s.sequence
: 序列号。NewSnowflake
方法:
Snowflake
实例,传入机器 ID,并校验该 ID 是否有效。main
方法:
Snowflake
实例并生成多个 ID,打印输出。假设我们运行上面的代码,生成并打印 10 个 ID,输出可能如下所示:
Generated ID: 1654767740152535040
Generated ID: 1654767740152540160
Generated ID: 1654767740152545280
Generated ID: 1654767740152550400
Generated ID: 1654767740152555520
Generated ID: 1654767740152560640
Generated ID: 1654767740152565760
Generated ID: 1654767740152570880
Generated ID: 1654767740152576000
Generated ID: 1654767740152581120
这些 ID 会按时间顺序递增,可以根据生成的 ID 推算出其生成的时间(通过时间戳部分)。同时,每个 ID 都是全局唯一的,适用于分布式系统中。
通过上述实现和原理分析,雪花算法为分布式系统提供了一种高效、简单且可靠的全局唯一 ID 生成方案。