在 Go 语言中,可以通过实现雪花算法(Snowflake)来生成分布式唯一ID。雪花算法是 Twitter 提出的一种生成分布式唯一ID的算法,其核心思想是将一个64位的ID划分为多个部分,分别表示时间戳、机器ID和序列号。
以下是雪花算法的 Go 语言实现:
1. 雪花算法结构
雪花算法的64位ID结构如下:
scss
| 1 bit (未使用) | 41 bits (时间戳) | 10 bits (机器ID) | 12 bits (序列号) |
- 时间戳:41位,表示从某个起始时间到当前时间的毫秒数。
- 机器ID:10位,用于标识不同的机器或节点。
- 序列号:12位,用于同一毫秒内生成多个ID。
2. Go 实现代码
以下是雪花算法的 Go 实现:
go
package main import ( "errors" "fmt" "sync" "time" ) const ( // 定义各部分的位数 epoch int64 = 1609459200000 // 起始时间:2021-01-01 00:00:00 UTC timestampBits uint8 = 41 machineIDBits uint8 = 10 sequenceBits uint8 = 12 // 定义最大值 maxMachineID int64 = -1 ^ (-1 << machineIDBits) maxSequence int64 = -1 ^ (-1 << sequenceBits) // 定义位移 timestampShift = machineIDBits + sequenceBits machineIDShift = sequenceBits ) // Snowflake 结构体 type Snowflake struct { mutex sync.Mutex lastStamp int64 machineID int64 sequence int64 } // NewSnowflake 创建一个 Snowflake 实例 func NewSnowflake(machineID int64) (*Snowflake, error) { if machineID < 0 || machineID > maxMachineID { return nil, errors.New("machine ID out of range") } return &Snowflake{ lastStamp: 0, machineID: machineID, sequence: 0, }, nil } // NextID 生成下一个唯一ID func (s *Snowflake) NextID() int64 { s.mutex.Lock() defer s.mutex.Unlock() // 获取当前时间戳 currentStamp := time.Now().UnixMilli() // 如果当前时间戳小于上次生成ID的时间戳,说明时钟回拨 if currentStamp < s.lastStamp { panic("clock moved backwards") } // 如果是同一毫秒内生成的ID,则递增序列号 if currentStamp == s.lastStamp { s.sequence = (s.sequence + 1) & maxSequence // 如果序列号溢出,则等待下一毫秒 if s.sequence == 0 { for currentStamp <= s.lastStamp { currentStamp = time.Now().UnixMilli() } } } else { // 如果不是同一毫秒,则重置序列号 s.sequence = 0 } // 更新上次生成ID的时间戳 s.lastStamp = currentStamp // 生成ID id := ((currentStamp - epoch) << timestampShift) | (s.machineID << machineIDShift) | s.sequence return id } func main() { // 创建一个 Snowflake 实例,机器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) } }
3. 代码说明
- 起始时间:
epoch是算法的起始时间,可以根据需要调整。 - 机器ID:
machineID用于标识不同的机器或节点,必须在[0, maxMachineID]范围内。 - 序列号:
sequence用于同一毫秒内生成多个ID,范围为[0, maxSequence]。 - 线程安全:使用
sync.Mutex确保并发安全。 - 时钟回拨处理:如果当前时间戳小于上次生成ID的时间戳,说明时钟回拨,直接抛出异常。
4. 示例输出
运行上述代码,会生成类似以下的唯一ID:
6928334669447168 6928334669447169 6928334669447170 6928334669447171 6928334669447172 6928334669447173 6928334669447174 6928334669447175 6928334669447176 6928334669447177
5. 优点
- 高性能:生成ID的速度非常快。
- 分布式:通过机器ID支持分布式部署。
- 有序性:ID 按时间递增,适合作为数据库主键。
6. 注意事项
- 机器ID分配:确保每台机器的
machineID唯一。 - 时钟同步:确保各机器的时钟同步,避免时钟回拨问题。
- ID长度:生成的ID是64位整数,适合大多数场景。