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

相关推荐
Coding君4 小时前
每日一Go-30、Go语言进阶-现代化部署:容器化与Docker
go
子玖6 小时前
go实现通过ip解析城市
后端·go
Das1_7 小时前
【Golang 数据结构】Slice 底层机制
后端·go
太凉1 天前
select 语句详解
go
想用offer打牌1 天前
一站式了解四种限流算法
java·后端·go
怕浪猫1 天前
第20章:Web服务实战——构建RESTful API
后端·go·编程语言
Coding君2 天前
每日一Go-28、Go语言进阶-深入Go运行时:内存管理与GC
go
echo本尊472182 天前
如何设计一个简单易用的定时任务模块
go
Bigger3 天前
告别版本焦虑:如何为 Hugo 项目定制专属构建环境
前端·架构·go