go小项目-实现雪花算法

雪花算法(Snowflake Algorithm)是Twitter开源的一种分布式ID生成算法,它可以生成全局唯一且有序的64位ID。


一、雪花算法的结构

雪花算法生成的64位ID由以下部分组成:

  1. 符号位(1位) :固定为0,表示正数。
  2. 时间戳(41位) :表示从某个起始时间(如2025年1月1日)到当前时间的毫秒数。
  3. 机器ID(10位) :表示生成ID的机器或节点,支持最多1024个节点。
  4. 序列号(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)
	}
}

三、代码解析

  1. Snowflake结构体

    • 包含生成ID所需的所有字段,如机器ID、序列号、上一次生成ID的时间戳等。
    • 使用sync.Mutex保证并发安全。
  2. 常量定义

    • 定义了机器ID、序列号的位数以及最大取值范围。
  3. NewSnowflake函数

    • 初始化雪花算法,检查机器ID是否在合法范围内。
  4. NextID方法

    • 生成下一个ID。
    • 处理时钟回拨问题。
    • 如果同一毫秒内生成的ID超出序列号范围,则等待下一毫秒。
  5. 主函数

    • 初始化雪花算法并生成10个ID。

四、运行结果

运行上述代码,会输出10个全局唯一且有序的64位ID,例如:

复制代码
129383475712 
129383475713 
129383475714 
129383475715 
129383475716 
129383475717 
129383475718 
129383475719 
129383475720 
129383475721 

五、注意事项

  1. 时钟回拨问题

    • 如果系统时间被回拨,可能会导致ID重复。代码中通过panic处理了这种情况,实际应用中可以根据需求选择更合适的处理方式(如等待或抛出异常)。
  2. 机器ID分配

    • 机器ID必须在0到1023之间,且每个节点必须分配唯一的ID。
  3. 性能优化

    • 雪花算法性能非常高,适合高并发场景。如果性能要求更高,可以进一步优化时间戳的获取方式。

通过Go语言实现雪花算法,可以轻松生成全局唯一且有序的ID。该算法简单高效,适合分布式系统中的ID生成需求。

相关推荐
郭京京5 小时前
go操作mysql数据库(database/sql)
go
郭京京6 小时前
go处理命令行参数
go
程序员爱钓鱼10 小时前
Go语言实战案例-创建模型并自动迁移
后端·google·go
hankeyyh1 天前
golang 易错点-slice copy
后端·go
亚洲第一中锋_哈达迪1 天前
深入理解 Go slice
go
郭京京2 天前
go语言sync.Map和atomic包
go
懒得更新2 天前
Go语言微服务架构实战:从零构建云原生电商系统
后端·go
程序员爱钓鱼2 天前
Go语言实战案例:执行基本的增删改查
后端·google·go
程序员爱钓鱼2 天前
Go语言实战案例:连接MySQL数据库
后端·google·go