常见的生成主键 id 的方式
生成主键方案:
- UUID
- 数据库自增主键
- 基于 Redis 生成全局 ID 策略
- 雪花算法,Twitter 的分布式自增 ID 算法 snowflake
- 百度 UidGenerator 算法(基于雪花算法实现自定义时间戳)
- 美团 Leaf 算法(依赖于数据库,ZK)
雪花算法的优缺点
优点
- 经测试 snowflake 每秒能生成 26 万个自增可排序的 ID。
- snowflake 生成的 ID 结果是一个 64bit 大小的整数,为一个 Long 型 (转换成字符串后长度最多 19)。
- 分布式系统内不会产生 ID 碰撞(datacenter 和 workerId 作区分)并且效率高。
- 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也非常高,可以根据自身业务分配 bit 位,非常灵活。
缺点
- 时间回拨问题:由于机器的时间是动态的调整的,有可能会出现时间跑到之前几毫秒,如果这个时候获取到了这种时间,则会出现数据重复。
- 机器 id 上限:机器 id 是固定的 bit,那么也就是对应的机器个数是有上限的,在有些业务场景下,需要所有机器共享同一个业务空间,那么 10bit 表示的 1024 台机器是不够的。
雪花算法的基本原理
-
第 1 位: 二进制中最高位为 1 的是负数,而在随机 ID 中,只能为正数,故该位只能为 0,无意义。
-
第 2 位~第 42 位: 共 41bit,是当前时间戳转换为二进制而来的。可以使用 69 年:year = (1L << 41) / (1000L _ 60 _ 60 _ 24 _ 365) = 69
-
第 43 位~第 52 位: 共 10bit,是当前机器(服务器)的 ID,其二进制数为 210 即 1024,所以使用雪花算法的服务最多可以同时部署在 1024 台服务器上。需要注意的是这里 10 位中的 5 位是给机房的,5 位是给机器(服务器)的,也就是一个雪花算法服务最多能部署在 25 个机房,每个机房最多有 2^5 个机器(服务器)。
-
第 53 位~第 64 位: 共 12bit,是毫秒内的序列号,即统一毫秒内生成的第几个 ID,其二进制数为 2^12 即 4096,所以同一雪花算法服务在同一毫秒内可生成 4096 个序列号 ID,如果超出了,就只能等待下一毫秒再生成。
将以上四个部分拼接起来做位或运算,就组成了一个 64 位的全局唯一 ID。
使用雪花算法生成 ID
下载雪花算法的开源库
go
go get github.com/sony/sonyflake生成 ID
go
package mainimport ( "fmt" "github.com/sony/sonyflake" "time")func main() { var setting sonyflake.Settings //设置起始时间 startTime, err := time.Parse("2006-01-02 15:04:05", "2023-01-01 00:00:01") if err != nil { fmt.Println(err.Error()) } setting.StartTime = startTime id := sonyflake.NewSonyflake(setting) userId, err := id.NextID() if err != nil { fmt.Println(err.Error()) } fmt.Println(userId)}运行结果如下:
powershell
PS D:\GolandProjects> go run main.go76846360686532097