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生成需求。

相关推荐
研究司马懿1 天前
【云原生】Gateway API高级功能
云原生·go·gateway·k8s·gateway api
梦想很大很大2 天前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰2 天前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘2 天前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤2 天前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt112 天前
AI DDD重构实践
go
Grassto4 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto6 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室7 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题7 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo