雪花算法源码解析

本文深入解析了雪花算法的实现原理,详细介绍了其64位ID如何通过位运算划分为时间戳、工作机器ID和自增序列号三部分,确保了全局唯一性。此外,还讲解了源码中的关键常量定义和位运算技巧,如时间回拨处理、序列号溢出检查等,展示了如何高效地生成不重复的ID。
摘要由CSDN通过智能技术生成

雪花算法源码解析

id的组成

雪花算法的id由64位组成,总共分为4部分,第一部分只有一位,是正负标识位,没有其他作用,第二部分由41位的时间戳,第三部分为工作机器id,第四部分为自增序列号
在这里插入图片描述

41位时间戳能表示毫秒级的时间为69年,意味着id在69年不重复(时钟不会滚)
10位工作机器id,这个10位可以自由调整,可以用来表示业务
12位自增序列号,表示同一毫秒内能生成的id的数量

源码解析

const (
	nodeIDBits     = uint64(10)
	sequenceBits   = uint64(12)
	nodeIDShift    = sequenceBits
	timestampShift = sequenceBits + nodeIDBits
  //11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 = -1
  //11111111 11111111 11111111 11111111 11111111 11111111 11110000 00000000 = -1 << 12
  //00000000 00000000 00000000 00000000 00000000 00000000 00001111 11111111 = -1 ^ (-1 << 12) 4095
	sequenceMask   = int64(-1) ^ (int64(-1) << sequenceBits)

	// ( 2012-10-28 16:23:42 UTC ).UnixNano() >> 20
  // 项目上线的时间
	twepoch = int64(1288834974288)
)

type guid int64

type guidFactory struct {
	sync.Mutex

	nodeID        int64
	sequence      int64
	lastTimestamp int64
	lastID        guid
}

func (f *guidFactory) NewGUID() (guid, error) {
	f.Lock()
	// divide by 1048576, giving pseudo-milliseconds
  // 伪毫秒,当前的时间戳
	ts := time.Now().UnixNano() >> 20
  
  // 时间小于上一次的时间,时钟回摆,返回异常,否则可能有重复的id
	if ts < f.lastTimestamp {
		f.Unlock()
		return 0, ErrTimeBackwards
	}
  // 相同的时间毫秒数,则使用最后的12位自增序列号
	if f.lastTimestamp == ts {
    // 计算新的序列号
		f.sequence = (f.sequence + 1) & sequenceMask
    // 序列号==0 说明 sequence=4095 超出最大范围
		if f.sequence == 0 {
			f.Unlock()
			return 0, ErrSequenceExpired
		}
	} else {
    // 不是相同的毫秒,则自增数为0
		f.sequence = 0
	}
  //赋值上次的时间毫秒数
	f.lastTimestamp = ts
  //计算id 
	id := guid(((ts - twepoch) << timestampShift) |
		(f.nodeID << nodeIDShift) |
		f.sequence)
  // 校验id的合法性
	if id <= f.lastID {
		f.Unlock()
		return 0, ErrIDBackwards
	}
  //更新上一个id
	f.lastID = id
	f.Unlock()
	return id, nil
}

通过位运算的方式,高效率的将64位的整形 拆分成几个部分,最后再将几个部分合并,得到最终的数。

基础知识

二进制 负数表示

负数为正数的补码,补码是反码+1,反码为原码取反

-1 
1 :    00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
1的反码:11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111110
1的补码:11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

异或运算(^)

两个位相同为0,相异为1

0 0 1 0 0 0 1 1
0 0 1 0 1 1 1 1
-----------------
0 0 0 0 1 1 0 0

或运算(|)

两个位都为0,结果为0

0 0 1 0 0 0 1 1
0 0 1 0 1 1 1 1
-----------------
0 0 1 0 1 1 1 1

与运算(&)

两个位都为1,结果为1

0 0 1 0 0 0 1 1
0 0 1 0 1 1 1 1
-----------------
0 0 1 0 0 0 1 1

左移 (<<)

各二进位全部左移若干位,高位丢弃,低位补0

1010 1110 << 2 = 1011 1000

右移(>>)

各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

//无符号
1010 1110 >> 2 = 0010 1110
//有符号负数
1010 1110 >> 2 = 1110 1011
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值