snowflake,雪花算法

雪花算法

雪花算法用一个64bit的数字表示其生成的ID

[0]   [0000000 00000000 00000000 00000000 00000000 00]   [000000 0000]   [0000 00000000]  

最高位弃用,该位表示数字的正负,一般置0。
后续 41 位表示时间戳。2的41次幂的范围,可以使用69年。按照时间戳生成的ID在整体的趋势上是递增的。

再后续 10 位表示机器ID,2的10次幂的范围,可以有1024台服务器。

低 12 位 表示序列号。序列号的意义是,同一毫秒内生成的第几个ID。很显然1毫秒内可以生成2的12次幂个序列号。即2的12次幂个ID,即4096个ID。超出则等下一毫秒再生成。

优点:
高效率,不重复
缺点:
严重依赖机器时间

                     - ->[nacos 服务注册中心] <--
                     |                         |----[发号器服务1]<---------.       
                     |                         |                          |        
[商品服务]-----------/------------------------->\-----[发号器服务2]<--------|----[zookeeper]    
                    |                           |                         |
                    |                           `--[法号器服务3]<----------'         
                    |                                   |
[订单服务]----------/------------------>------------------

若发生时钟回拨情况的解决方案,该时间根据具体业务场景而定。
回拨时间很短( <= 100ms ),等待相应毫秒
回拨时间适中( > 100ms <= 1s ),将最近1s分成1000ms,将每1毫秒中最大的ID放入hash map,当发生回拨的时候,取出对应毫秒的最大ID,做自增操作,生成新的ID。
回拨时间较长(> 1s <= 5s),切换ID发放服务。
回拨时间很长( > 5s ),让该服务下线,发信息给运维人员,人工维护。

ID发放,在分布式微服务架构中通常需要单独的部署与维护,在ID发放服务少的情况下,可以通过配置文件,指定machineID(机房ID),若机器增多,可使用zookeeper生成唯一的进程ID,实现对machineID的控制。

代码

简单实现

package main

import (
	"fmt"
	"sync"
	"time"
)

type snowFlake struct {
	sync.Mutex
	lastMilliSecond int64
	currentMilSecId uint64
}

func (s *snowFlake) generate(machineID int) uint64 {

	s.Lock()
	defer s.Unlock()

	machineID &= 1<<10 - 1

	low12bit := s.currentMilSecId
	nowMicro := time.Now().UnixMicro()
	if nowMicro/1000 < s.lastMilliSecond {
	    panic("发生时钟回拨")
    }

	if last := s.lastMilliSecond; nowMicro/1000 == last { // 同一毫秒
		if s.currentMilSecId < 1<<12 {
			s.currentMilSecId++
			low12bit = s.currentMilSecId
		} else {
			time.Sleep(time.Microsecond * time.Duration(1+nowMicro-last*1000))
			nowMicro = time.Now().UnixMicro()
		}
	} else {
		s.currentMilSecId = 0
	}
	s.lastMilliSecond = nowMicro / 1000

	id := uint64(nowMicro)<<22 | uint64(machineID)<<12 | low12bit
	return id &^ (1 << 63) // 高位简单处理一下
}

func main() {
	s := snowFlake{}
	for i := 0; i < 1000; i++ {
		go func() {
			fmt.Printf("%b\n", s.generate(3))
		}()
	}
	time.Sleep(time.Second)
}
//10110001 00000011 01100100 10100010 00010100 00000000 01100000 0111100
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值