【golang】雪花算法的介绍和使用

snowflake

github地址:https://github.com/bwmarrin/snowflake

snowflake 是一个 Go 包,提供
  • 一个非常简单的推特雪花生成器。
  • 分析现有雪花 ID 的方法。
  • 将雪花 ID 转换为其他几种数据类型并返回的方法。
  • JSON 封送/取消封送函数,用于在 JSON API 中轻松使用雪花 ID。
  • 单调时钟计算可防止时钟漂移。
地位

这个包应该被认为是稳定和完整的。任何添加的内容 未来将强烈避免对现有函数进行 API 更改。

ID格式

默认情况下,ID 格式遵循原始的 Twitter 雪花格式。

整个 ID 是一个 63 位整数,存储在 int64 中
41 位用于使用自定义纪元以毫秒精度存储时间戳。
10 位用于存储节点 ID - 范围从 0 到 1023。
12 位用于存储序列号 - 范围从 0 到 4095。
自定义格式
您可以更改用于节点 ID 和步数(序列)的位数 通过设置雪花。节点位和雪花。步比特值。记住 这两者之间最多可以共享 22 位 值。您不必使用所有 22 位。

自定义纪元

默认情况下,此软件包使用 1288834974657 或 Nov 04 2010 01:42:54 的 Twitter 纪元。 您可以通过设置雪花来设置自己的纪元值。纪元到以毫秒为单位的时间 用作纪元。

自定义备注

设置自定义纪元或位值时,需要在调用之前设置它们 雪花包上的任何函数,包括 NewNode()。否则 您设置的自定义值将无法正确应用。

它是如何工作的

每次生成 ID 时,它都会像这样工作:

  • 毫秒精度的时间戳使用 41 位 ID 存储。
  • 然后将节点 ID 添加到后续位中。
  • 然后添加序列号,从 0 开始,并在同一毫秒内生成的每个 ID 递增。-如果您在序列滚动或溢出的同一毫秒内生成足够的 ID,则生成函数将暂停到下一毫秒。
    默认的推特格式如下所示。
+--------------------------------------------------------------------------+
| 1 Bit Unused | 41 Bit Timestamp |  10 Bit NodeID  |   12 Bit Sequence ID |
+--------------------------------------------------------------------------+

使用默认设置,这允许每个节点 ID 每毫秒生成 4096 个唯一 ID。

开始使用

  • 安装
    这假设你已经有一个有效的 Go 环境,如果没有,请先查看此页面
go get github.com/bwmarrin/snowflake
  • 用法
    将包导入到项目中,然后使用 唯一的节点号。默认设置允许节点号范围从 0 到 1023。 如果您设置了自定义节点位值,则需要计算您的 节点编号范围将是。使用节点对象调用 Generate() 方法来 生成并返回唯一的雪花 ID。

请记住,您创建的每个节点都必须具有唯一的节点编号,即使 跨多个服务器。如果不保持节点号唯一,生成器 无法保证所有节点的唯一 ID。

  • 示例程序:
package main

import (
	"fmt"

	"github.com/bwmarrin/snowflake"
)

func main() {

	// Create a new Node with a Node number of 1
	node, err := snowflake.NewNode(1)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Generate a snowflake ID.
	id := node.Generate()

	// Print out the ID in a few different ways.
	fmt.Printf("Int64  ID: %d\n", id)
	fmt.Printf("String ID: %s\n", id)
	fmt.Printf("Base2  ID: %s\n", id.Base2())
	fmt.Printf("Base64 ID: %s\n", id.Base64())

	// Print out the ID's timestamp
	fmt.Printf("ID Time  : %d\n", id.Time())

	// Print out the ID's node number
	fmt.Printf("ID Node  : %d\n", id.Node())

	// Print out the ID's sequence number
	fmt.Printf("ID Step  : %d\n", id.Step())

  // Generate and print, all in one.
  fmt.Printf("ID       : %d\n", node.Generate().Int64())
}
Int64  ID: 1630021738207121408
String ID: 1630021738207121408
Base2  ID: 1011010011111000000000010001001111010000000000001000000000000
Base64 ID: MTYzMDAyMTczODIwNzEyMTQwOA==
ID Time  : 1677462441385
ID Node  : 1
ID Step  : 0
ID       : 1630021738207121409





在项目中使用

package snowflake

import (
	"time"

	sf "github.com/bwmarrin/snowflake"
)

var node *sf.Node

func Init(startTime string, machineID int64) (err error) {
	var st time.Time
	st, err = time.Parse("2006-01-02", startTime)
	if err != nil {
		return
	}
	sf.Epoch = st.UnixNano() / 1000000
	node, err = sf.NewNode(machineID)
	return
}

func GenID() int64 {
	return node.Generate().Int64()
}

主程序中使用Init函数进行初始化

if err := snowflake.Init(settings.Conf.StartTime, settings.Conf.MachineID); err != nil {
	fmt.Printf("init sonwflake failed, err: %v\n", err)
	return
}

调用GenID()即可获得一个ID实例:

genID := GenID()
fmt.Printf("genID: %v\n", genID)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
雪花算法是一种分布式唯一ID生成算法,它可以保证在分布式环境下生成唯一的ID。在Golang中,我们可以使用以下代码实现雪花算法: ```go package main import ( "errors" "fmt" "sync" "time" ) const ( // StartTime 是雪花算法开始时间戳,用于减小生成的ID长度 StartTime = 1577808000000 // 2020-01-01 00:00:00的时间戳,单位毫秒 // MachineIDBits 机器ID的位数 MachineIDBits = 10 // SequenceBits 序列号的位数 SequenceBits = 12 // MachineIDShift 机器ID的移位长度 MachineIDShift = SequenceBits // TimestampShift 时间戳的移位长度 TimestampShift = SequenceBits + MachineIDBits // MaxMachineID 最大机器ID MaxMachineID = -1 ^ (-1 << MachineIDBits) // MaxSequence 最大序列号 MaxSequence = -1 ^ (-1 << SequenceBits) ) // Snowflake 是雪花算法生成的唯一ID结构体 type Snowflake struct { machineID int64 // 机器ID sequence int64 // 序列号 lastStamp int64 // 上次生成ID的时间戳 idLock sync.Mutex } // NewSnowflake 创建一个新的雪花算法实例 func NewSnowflake(machineID int64) (*Snowflake, error) { if machineID < 0 || machineID > MaxMachineID { return nil, errors.New("machine ID out of range") } return &Snowflake{ machineID: machineID, }, nil } // Generate 生成一个新的唯一ID func (s *Snowflake) Generate() int64 { s.idLock.Lock() defer s.idLock.Unlock() // 获取当前时间戳 now := time.Now().UnixNano() / 1e6 // 如果当前时间小于上次生成ID的时间戳,说明系统时间被调整过,此时应该返回错误 if now < s.lastStamp { panic(fmt.Sprintf("time is moving backwards, refusing to generate id for %d milliseconds", s.lastStamp-now)) } // 如果当前时间与上次生成ID的时间戳相同,说明在同一毫秒内生成了多次ID,此时应将序列号+1 if now == s.lastStamp { s.sequence = (s.sequence + 1) & MaxSequence if s.sequence == 0 { // 序列号已经达到最大值,等待下一毫秒 for now <= s.lastStamp { now = time.Now().UnixNano() / 1e6 } } } else { // 当前时间与上次生成ID的时间戳不同,说明已经进入下一毫秒,序列号重置为0 s.sequence = 0 } // 保存当前时间戳,用于下一次生成ID时使用 s.lastStamp = now // 生成ID id := (now-StartTime)<<TimestampShift | (s.machineID << MachineIDShift) | s.sequence return id } func main() { // 创建一个新的雪花算法实例,机器ID为1 sf, err := NewSnowflake(1) if err != nil { panic(err) } // 生成10个唯一ID for i := 0; i < 10; i++ { id := sf.Generate() fmt.Println(id) } } ``` 在上面的代码中,我们首先定义了一些常量,括开始时间、机器ID的位数、序列号的位数等。然后,我们定义了一个Snowflake结构体,用于保存生成ID时需要用到的一些参数,如机器ID、序列号、上次生成ID的时间戳等。接着,我们定义了NewSnowflake函数,用于创建一个新的雪花算法实例,并检查机器ID是否超出范围。最后,我们定义了Generate函数,用于生成一个新的唯一ID。在Generate函数中,我们首先获取当前时间戳,然后判断当前时间是否小于上次生成ID的时间戳,如果是,则说明系统时间被调整过,此时应该返回错误;如果当前时间与上次生成ID的时间戳相同,则说明在同一毫秒内生成了多次ID,此时应将序列号+1;如果当前时间与上次生成ID的时间戳不同,则说明已经进入下一毫秒,序列号重置为0。最后,我们将当前时间戳、机器ID、序列号组合成一个64位的唯一ID返回。 在main函数中,我们创建了一个新的雪花算法实例,并调用Generate函数生成了10个唯一ID。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值