Snowflake 算法 Go 语言实现:分布式 ID 生成解决方案
在分布式系统中,为每个实体生成唯一标识符(ID)是一个常见的需求。这种唯一标识符通常用于数据库主键、缓存键、消息队列的唯一标识等场景。Snowflake 算法是一种简单且高效的分布式 ID 生成方案,它能够保证 ID 的全局唯一性,并且具有高性能和可扩展性。
本文将介绍 Snowflake 算法的原理,并使用 Go 语言实现一个简单的 Snowflake ID 生成器。
Snowflake 算法原理
Snowflake 算法由 Twitter 的工程师设计,它将时间戳、数据中心 ID、机器 ID 和序列号组合成一个 64 位的整数。以下是 Snowflake 算法的组成部分:
1. 时间戳(41 位):使用毫秒级时间戳,41 位可以表示 2^41 毫秒,即 69 年。
2. 数据中心 ID(5 位):表示数据中心 ID,5 位可以表示 2^5 个数据中心。
3. 机器 ID(5 位):表示机器 ID,5 位可以表示 2^5 个机器。
4. 序列号(12 位):表示同一毫秒内生成的 ID 序列,12 位可以表示 2^12 个序列。
将这四部分组合起来,可以得到一个 64 位的 Snowflake ID。
Go 语言实现
下面是使用 Go 语言实现的 Snowflake ID 生成器:
go
package main
import (
"fmt"
"sync"
"time"
)
const (
timestampBits = 41
datacenterIdBits = 5
机器IdBits = 5
sequenceBits = 12
maxDatacenterId = 1 << datacenterIdBits
maxMachineId = 1 << 机器IdBits
maxSequence = 1 << sequenceBits
timeOffset = int64(time.Now().UnixMilli() - epoch)
datacenterId int64
机器Id int64
sequence int64
lastTimestamp int64
mu sync.Mutex
)
func init() {
// 初始化数据中心 ID 和机器 ID
datacenterId = 1
机器Id = 1
sequence = 0
lastTimestamp = -1
}
func genSnowflakeId() int64 {
mu.Lock()
defer mu.Unlock()
now := time.Now().UnixMilli()
if now < lastTimestamp {
panic("Clock moved backwards. Refusing to generate id.")
}
if lastTimestamp == now {
sequence = (sequence + 1) & maxSequence
if sequence == 0 {
now = tilNextMillis(lastTimestamp)
}
} else {
sequence = 0
}
lastTimestamp = now
id := ((now-int64(timeOffset))<<timestampBits) | (datacenterId<<datacenterIdBits) | (机器Id<<机器IdBits) | sequence
return id
}
func tilNextMillis(lastTimestamp int64) int64 {
t := time.Now().UnixMilli()
for t <= lastTimestamp {
t = time.Now().UnixMilli()
}
return t
}
func main() {
for i := 0; i < 10; i++ {
fmt.Println(genSnowflakeId())
}
}
代码解析
1. 定义常量:定义了时间戳、数据中心 ID、机器 ID 和序列号的位数,以及最大值。
2. 初始化:初始化数据中心 ID、机器 ID、序列号和最后的时间戳。
3. 生成 ID:获取当前时间戳,判断是否为同一毫秒,如果是则增加序列号,否则重置序列号并获取下一个时间戳。将时间戳、数据中心 ID、机器 ID 和序列号组合成 ID。
4. 等待下一个毫秒:如果当前时间戳小于最后的时间戳,则等待下一个毫秒。
总结
本文介绍了 Snowflake 算法的原理,并使用 Go 语言实现了一个简单的 Snowflake ID 生成器。通过这种方式,我们可以轻松地生成全局唯一的 ID,适用于分布式系统中的各种场景。在实际应用中,可以根据需求调整数据中心 ID、机器 ID 和序列号的位数,以满足不同的业务需求。
Comments NOTHING