雪花算法(Snowflake Algorithm)是Twitter开源的一种分布式ID生成算法,它可以生成全局唯一且有序的64位ID。
一、雪花算法的结构
雪花算法生成的64位ID由以下部分组成:
- 符号位(1位) :固定为0,表示正数。
- 时间戳(41位) :表示从某个起始时间(如2025年1月1日)到当前时间的毫秒数。
- 机器ID(10位) :表示生成ID的机器或节点,支持最多1024个节点。
- 序列号(12位) :表示同一毫秒内生成的ID序号,支持每毫秒生成4096个ID。
二、Go语言实现雪花算法
go
package main
import (
"errors"
"fmt"
"sync"
"time"
)
// Snowflake 结构体
type Snowflake struct {
mu sync.Mutex // 互斥锁,保证并发安全
startTime int64 // 起始时间(毫秒)
machineID int64 // 机器ID
sequence int64 // 序列号
lastTimestamp int64 // 上一次生成ID的时间戳
}
// 常量
const (
machineIDBits = 10 // 机器ID占用的位数
sequenceBits = 12 // 序列号占用的位数
machineIDShift = sequenceBits // 机器ID左移位数
timestampShift = machineIDBits + sequenceBits // 时间戳左移位数
maxMachineID = -1 ^ (-1 << machineIDBits) // 最大机器ID
maxSequence = -1 ^ (-1 << sequenceBits) // 最大序列号
)
// NewSnowflake 初始化雪花算法
func NewSnowflake(machineID int64) (*Snowflake, error) {
if machineID < 0 || machineID > maxMachineID {
return nil, errors.New("machine ID out of range")
}
return &Snowflake{
startTime: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC).UnixNano() / 1e6,
machineID: machineID,
sequence: 0,
lastTimestamp: -1,
}, nil
}
// NextID 生成下一个ID
func (s *Snowflake) NextID() int64 {
s.mu.Lock()
defer s.mu.Unlock()
// 获取当前时间戳
currentTimestamp := time.Now().UnixNano() / 1e6
// 如果当前时间小于上一次生成ID的时间,说明时钟回拨
if currentTimestamp < s.lastTimestamp {
panic("clock moved backwards")
}
// 如果是同一毫秒内生成的ID
if currentTimestamp == s.lastTimestamp {
s.sequence = (s.sequence + 1) & maxSequence
if s.sequence == 0 { // 如果序列号超出范围,等待下一毫秒
for currentTimestamp <= s.lastTimestamp {
currentTimestamp = time.Now().UnixNano() / 1e6
}
}
} else {
s.sequence = 0
}
// 更新上一次生成ID的时间戳
s.lastTimestamp = currentTimestamp
// 生成ID
id := (currentTimestamp-s.startTime)<<timestampShift |
(s.machineID << machineIDShift) |
s.sequence
return id
}
func main() {
// 初始化雪花算法,机器ID为1
snowflake, err := NewSnowflake(1)
if err != nil {
panic(err)
}
// 生成10个ID
for i := 0; i < 10; i++ {
id := snowflake.NextID()
fmt.Println(id)
}
}
三、代码解析
-
Snowflake
结构体- 包含生成ID所需的所有字段,如机器ID、序列号、上一次生成ID的时间戳等。
- 使用
sync.Mutex
保证并发安全。
-
常量定义
- 定义了机器ID、序列号的位数以及最大取值范围。
-
NewSnowflake
函数- 初始化雪花算法,检查机器ID是否在合法范围内。
-
NextID
方法- 生成下一个ID。
- 处理时钟回拨问题。
- 如果同一毫秒内生成的ID超出序列号范围,则等待下一毫秒。
-
主函数
- 初始化雪花算法并生成10个ID。
四、运行结果
运行上述代码,会输出10个全局唯一且有序的64位ID,例如:
129383475712
129383475713
129383475714
129383475715
129383475716
129383475717
129383475718
129383475719
129383475720
129383475721
五、注意事项
-
时钟回拨问题
- 如果系统时间被回拨,可能会导致ID重复。代码中通过
panic
处理了这种情况,实际应用中可以根据需求选择更合适的处理方式(如等待或抛出异常)。
- 如果系统时间被回拨,可能会导致ID重复。代码中通过
-
机器ID分配
- 机器ID必须在0到1023之间,且每个节点必须分配唯一的ID。
-
性能优化
- 雪花算法性能非常高,适合高并发场景。如果性能要求更高,可以进一步优化时间戳的获取方式。
通过Go语言实现雪花算法,可以轻松生成全局唯一且有序的ID。该算法简单高效,适合分布式系统中的ID生成需求。