雪花算法如何生成用户ID?有什么高明之处?
Posted 了 凡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了雪花算法如何生成用户ID?有什么高明之处?相关的知识,希望对你有一定的参考价值。
博主简介
-- 本人 了 凡 ,意义是希望本人任何时候以善良为先,以人品为重,喜欢了凡四训中的立命之学、改过之法、积善之方、谦德之效四训。微信公众号【了凡银河系】期待你的关注。未来我们一起加油!
前言
雪花算法生成用户ID
分布式ID生成器
分布式ID的特点
- 全局唯一性:不能出现有重复的ID标识,这是基本要求。
- 递增性:确保生成ID对于用户或业务是递增的。
- 高可用性:确保任何时候都能生成正确的ID。
- 高性能性:在高并发的环境下依然表现良好。
snowflake算法介绍
雪花算法,它是Twitter开源的由64位整数组成分布式ID,性能较高,并且在单机上递增。
设计思想
-
第一位 占用1bit,其值始终是0,没有实际作用。
-
时间戳 占用41bit,单位为毫秒,总共可以容纳约69年的时间。当然,我们的时间毫秒计数不会真的从1970年开始记,那样我们的系统跑到 2039/9/7 23:47:35 就不能用了,所以这里的时间戳只是相对于某个时间的增量,比如我们的系统上线是2020-07-01,那么我们完全可以把这个timestamp当作是从 2020-07-01 00:00:00.000 的偏移量。
-
工作机器id 占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,最多可以容纳1024个节点。
-
序列号 占用12bit,用来记录同毫秒内产生的不同id。每个节点每毫秒O开始不断累加,最多可以累加到4095,同一毫秒一共可以产生4096个ID。
SnowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢?
同一毫秒的ID数量=1024 X 4096= 4194304
snowflake的Go实现
链接: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?有什么高明之处?的主要内容,如果未能解决你的问题,请参考以下文章