雪花算法如何生成用户ID?有什么高明之处?

Posted 了 凡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了雪花算法如何生成用户ID?有什么高明之处?相关的知识,希望对你有一定的参考价值。

博主简介

-- 本人 了 凡 ,意义是希望本人任何时候以善良为先,以人品为重,喜欢了凡四训中的立命之学、改过之法、积善之方、谦德之效四训。微信公众号【了凡银河系】期待你的关注。未来我们一起加油!

前言



雪花算法生成用户ID

分布式ID生成器

分布式ID的特点

  • 全局唯一性:不能出现有重复的ID标识,这是基本要求。
  • 递增性:确保生成ID对于用户或业务是递增的。
  • 高可用性:确保任何时候都能生成正确的ID。
  • 高性能性:在高并发的环境下依然表现良好。

snowflake算法介绍

雪花算法,它是Twitter开源的由64位整数组成分布式ID,性能较高,并且在单机上递增。

设计思想

  1. 第一位 占用1bit,其值始终是0,没有实际作用。

  2. 时间戳 占用41bit,单位为毫秒,总共可以容纳约69年的时间。当然,我们的时间毫秒计数不会真的从1970年开始记,那样我们的系统跑到 2039/9/7 23:47:35 就不能用了,所以这里的时间戳只是相对于某个时间的增量,比如我们的系统上线是2020-07-01,那么我们完全可以把这个timestamp当作是从 2020-07-01 00:00:00.000 的偏移量。

  3. 工作机器id 占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,最多可以容纳1024个节点。

  4. 序列号 占用12bit,用来记录同毫秒内产生的不同id。每个节点每毫秒O开始不断累加,最多可以累加到4095,同一毫秒一共可以产生4096个ID。

SnowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢?
同一毫秒的ID数量=1024 X 4096= 4194304

snowflake的Go实现

Twitter

链接:https://github.com/bwmarrin/snowflake
github.com/bwmarrin/snowflake 是一个相当轻量化的snowflake的Go实现。

import (
   "fmt"
   _ "github.com/onsi/gomega"
   "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()
}

func main() {
   if err := Init("2020-07-10",1); err != nil {
      fmt.Printf("init failed, err:%v\\n", err)
      return
   }
   id := GenID()
   fmt.Println(id)
}

索尼

链接:https://github.com/sony/snowflake
sonyflake是Sony公司的一个开源项目,基本思路和snowflake差不多,不过位分配上稍有不同:

这里的时间只用了39个bit,但时间的单位变成了10ms,所以理论上比41位表示的时间还要久(174年)。
Sequence ID 和之前的定义一致,Machine ID 其实就是节点id。sonyflake 库有以下配置参数:

type Settings struct {
   StartTime      time.Time
   MachineID      func() (uint16, error)
   CheckMachineID  func(uint16) bool
}

其中:

  • StartTime 选项和我们之前的 Epoch 差不多,如果不设置的话,默认是从 2014-09-0100 :00:00 +0000 UTC 开始。
  • MachineID 可以由用户自定义的函数,如果用户不定义的话,会默认将本机IP的低16位作为 machine id。
  • CheckMachineID 是由用户提供的检查 MachineID 是否冲突的函数。

使用示例:

import (
   "fmt"
   _ "github.com/onsi/gomega"
   "time"
   
   "github.com/sony/sonyflake"
)

var (
   sonyFlake     *sonyflake.Sonyflake
   sonyMachineID  uint16
)

func getMachineID() (uint16, error)  {
   return sonyMachineID, nil
}

// 需传入当前的机器ID
func Init(startTime string, machineId uint16) (err error)  {
   sonyMachineID = machineId
   var st time.Time
   st, err = time.Parse("2006-01-02", startTime)
   if err != nil {
      return err
   }
   settings := sonyflake.Settings{
      StartTime: st,
      MachineID: getMachineID,
   }
   sonyFlake = sonyflake.NewSonyflake(settings)
   return
}


// GenID 生成id
func GenID() (id uint16, err error)  {
   if sonyFlake == nil {
      err = fmt.Errorf("sony flake not inited")
      return
   }
   id, err = sonyFlake.NextID()
   return
}

这次就先讲到这里,如果想要了解更多的golang语言内容一键三连后序每周持续更新!

以上是关于雪花算法如何生成用户ID?有什么高明之处?的主要内容,如果未能解决你的问题,请参考以下文章

分布式系统的唯一ID如何生成

分布式系统的唯一ID如何生成

spring boot中使用雪花算法生成雪花ID

Rust实现雪花算法生成唯一ID方案

雪花算法源码

雪花算法生成的ID在返回给前端之后和生成的不一样,到底是什么原因?