在高并发场景中,通常需要像mysql中那样的自增主键一样的不会重复且自增的id生成
twitter的snowflake就是一种典型的解法,id数值长64位,是一个int64类型,被分为四个部分:
- 最高位不使用
- 41位表示收到请求的时间戳,单位为毫秒
- 5位表示数据中心的id
- 5位表示机器实例的id
- 12位循环自增id,1111,1111,1111后归零
这样的机制可以保证一台机器在一毫秒内产生4096条消息,一秒总共409.6万条消息
数据中心id配合实例id一共有10位,每个数据中心可以部署32台实例,搭建32个数据中心,所以一共存在1024个实例
41位时间戳可以使用69年
1. github.com/bwmarrin/snowflake
github.com/bwmarrin/snowflake是一个轻量级的snowflake实现
首先需要引入依赖
go get github.com/bwmarrin/snowflake
这个库使用起来也非常简单
func main(){ node,err:=snowflak.NewNode(1) if err!=nil{ println(err.Error()) os.Exit(1) } for i:=0;i<20;i++{ id:=node.Generate() fmt.Printf("int64 ID: %d\n",id) fmt.Printf("string ID: %s\n",id) fmt.Printf("base2 ID: %s\n",id.Base2()) fmt.Printf("base64 ID: %s\n",id.Base64()) fmt.Printf("ID time: %d\n",id.Time()) fmt.Printf("ID node: %d\n",id.Node()) fmt.Printf("ID step: %d\n",id.Step()) fmt.Println("--------------------------------") } }
这个库是一个单文件,其中提供了我们可以定制的参数
其中Epoch是起始时间、NodeBits是实例id的长度,默认10位、StepBits是自增id的长度,默认12位
2. github.com/sony/sonyflake
snoyflake侧重于多主机多实例的生命周期和性能,所以与snowflake使用了不同的位分配:
- 比snowflake更长的生命周期,174年
- 能运行在更多的实例上,216个
- 生成id的速度比snowflake慢,10ms内最多生成28个
snoyflake在启动阶段需要配置参数,主要是一个Setting结构体
type Settings struct { StartTime time.Time // 起始时间,默认2014-09-01 00:00:00 +0000 UTC MachineID func() (uint16, error) // 返回实例ID的函数,如果不定义此函外,默认用本机ip的低16位 CheckMachineID func(uint16) bool // 验证实例ID/计算机ID的唯一性,返回true时才创建 }
我们需要自己实现这两个函数:
func getMachineID() (uint16, error) { var machineID uint16 = 6 return machineID, nil } func checkMachineID(machineID uint16) bool { existsMachines := []uint16{1, 2, 3, 4, 5} for _, v := range existsMachines { if v == machineID { return false } } return true }
func main() { t, _ := time.Parse("2006-01-02", "2021-01-01") settings := sonyflake.Settings{ StartTime: t, MachineID: getMachineID, CheckMachineID: checkMachineID, } sf := sonyflake.NewSonyflake(settings) for i := 0; i < 10; i++ { id, err := sf.NextID() if err != nil { fmt.Println(err) os.Exit(1) } fmt.Println(id) } }