go雪花算法

本文介绍了雪花算法,一种生成64位ID的方法,利用时间戳、机器标识和序列号确保ID唯一且有序。文章讨论了其优点如高效生成、无依赖性和基本有序性,同时提到了Sonyflake的差异。还展示了如何在项目中使用Twitter的snowflake库生成ID。
摘要由CSDN通过智能技术生成

雪花算法是为了得到不同的id存在的,世界上没有两片相同的雪花,这也是雪花算法得名由来。

雪花算法的逻辑

雪花算法的得到id先叫雪花id吧,他由64位bit组成

  • 首位保留位不用默认位0(固定)
  • 41位时间戳(当前时间截 – 开始时间截)
  • 10位机器位(不同机器上面不同,故最多部署在2的10次方,1024台机器上面)
  • 12位bit序列号(用来记录同毫秒内产生的不同id,同一机器同一时间可产生4096个号)

雪花算法的到id的优缺点

1.系统环境ID不重复(由时间戳机器号,序列号保证,除非大需求情况,这种情况基本不存在

能满足高并发分布式系统环境ID不重复,比如大家熟知的分布式场景下的数据库表的ID生成。

2.生成效率极高(409.6w/s)

在高并发,以及分布式环境下,除了生成不重复 id,每秒可生成百万个不重复 id,生成效率极高。

3.保证基本有序递增

基于时间戳,可以保证基本有序递增,很多业务场景都有这个需求。

4.不依赖第三方库

不依赖第三方的库,或者中间件,算法简单,在内存中进行。

5.依赖服务器时间,服务器时钟回拨时可能会生成重复 id

sonyflake与雪花算法类似,位数分配不同有差别

项目中简单使用(使用推特写好的库github.com/bwmarrin/snowflake)

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()
}

使用这个包里面的GenID生成id

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
雪花算法是一种分布式唯一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。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值