栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

分布式唯一ID的生成之雪花算法(Go实现)

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

分布式唯一ID的生成之雪花算法(Go实现)

分布式唯一ID的生成

背景:

在分布式架构下,唯一序列号生成是我们在设计一个尤其是数据库使用分库分表的时候会常见的一个问题

特性:

  1. 全局唯一,这是基本要求,不能出现重复
  2. 数字类型,趋势递增,后面的ID必须比前面的大
  3. 长度短,能够提高查询效率,这也是从MySQL数据库规范出发的,尤其是ID作为主键时
  4. **信息安全,**如果ID连续生成,势必会泄露业务信息,所以需要无规则不规则
  5. 高可用低延时,ID生成快,能够扛住高并发,延时足够低不至于成为业务瓶颈.

雪花算法:

​ snowflake是推特开源的分布式ID生成算法

  1. 结果: long 型的ID号(64位的ID号)

  2. 核心思想(生成的ID号是64位那么就对64位进行划分赋予特别的含义):

    41bit-时间戳决定了该算法生成ID号的可用年限.

    10bit-工作机器编号决定了该分布式系统的扩容性即机器数量.

    12bit-序列号决定了每毫秒单机系统可以生成的序列号

  3. 拓展:什么是时间戳?

    北京时间1970年01月01日08时00分00秒到此时时刻的总秒数

  4. 优势:

//实现方法:
package main


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



type SnowFlake struct{
	mu sync.Mutex
	//雪花算法开启时的起始时间戳
	twepoch int64

	//每一部分占用的位数
	workerIdBits     int64 //每个数据中心的工作机器的编号位数
	datacenterIdBits int64 //数据中心的编号位数
	sequenceBits     int64 //每个工作机器每毫秒递增的位数

	//每一部分最大的数值
	maxWorkerId int64
	maxDatacenterId int64
	maxSequence int64

	//每一部分向左移动的位数
	workerIdShift int64
	datacenterIdShift int64
	timestampShift int64

	//当前数据中心ID号
	datacenterId int64
	//当前机器的ID号
	workerId int64
	//序列号
	sequence int64
	//上一次生成ID号前41位的毫秒时间戳
	lastTimestamp int64
}


func (s *SnowFlake)timeGen()int64{
	return time.Now().UnixMilli()
}

func (s *SnowFlake)tilNextMills()int64{
	timeStampMill:=s.timeGen()
	for timeStampMill<=s.lastTimestamp{
		timeStampMill=s.timeGen()
	}
	return timeStampMill
}
func (s *SnowFlake)NextId()(int64,error){
	s.mu.Lock()
	defer s.mu.Unlock()
	nowTimestamp:=s.timeGen()//获取当前的毫秒级别的时间戳
	if nowTimestamp=mySnow.maxWorkerId||datacenterId>=mySnow.maxDatacenterId{
		return nil,errors.New("workerId or datacenterId must not higher than max value ")
	}
	mySnow.workerIdShift=mySnow.sequenceBits
	mySnow.datacenterIdShift=mySnow.sequenceBits+mySnow.workerIdBits
	mySnow.timestampShift=mySnow.sequenceBits+mySnow.workerIdBits+mySnow.datacenterIdBits

	mySnow.lastTimestamp=-1
	mySnow.workerId=workerId
	mySnow.datacenterId=datacenterId

	return mySnow,nil
}



func main(){
	//模拟实验是生成并发400W个ID,所需要的时间
	mySnow,_:=NewSnowFlake(0,0)//生成雪花算法
	group:=sync.WaitGroup{}
	startTime:=time.Now()
	generateId:=func (s SnowFlake,requestNumber int){
		for i:=0;i 

以上分析生成400WID号只需要803.1006ms(所以单机上可以每秒生成的ID数在400W以上)

优点:

  1. 毫秒数在高位,自增序列在低位,整个ID都是趋势递增
  2. 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成的ID性能也是非常高的
  3. 可以根据自身业务特性分配bit位,非常灵活

缺陷:

1. 依赖机器时钟,如果**机器时钟回拨**,会导致重复ID生成.
1. 在单机上是递增的,但是由于设计到分布式环境下,每台机器上的时钟不可能完全同步,有时候会出现不是全局递增的情况.

如何解决单机系统中时钟回拨问题:

​ 可以分为两种情况:

1. 如果**时间回拨时间较短,比如配置5ms以内**,那么可以直接等候一定的时间,让机器时间追上来
1. 如果**时间回拨时间较长**,我们不能接收这么长的阻塞等候,那么就有两个策略,直接拒绝,抛出异常;或者通过RD时钟回滚

布式环境下,每台机器上的时钟不可能完全同步,有时候会出现不是全局递增的情况.

如何解决单机系统中时钟回拨问题:

​ 可以分为两种情况:

1. 如果**时间回拨时间较短,比如配置5ms以内**,那么可以直接等候一定的时间,让机器时间追上来
1. 如果**时间回拨时间较长**,我们不能接收这么长的阻塞等候,那么就有两个策略,直接拒绝,抛出异常;或者通过RD时钟回滚

参考博客高并发情况下,雪花ID一秒400W个,以及分布式ID算法(详析)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/944497.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号