Snowflake 中文的意思为雪花,所以 Snowflake算法 常被称为 雪花算法,是 Twitter(现“X”)开源的分布式 ID 生成算法,是一种分布式主键ID生成的解决方案。
雪花算法
生成后是一个 64bit 的 long 型的数值,组成部分引入了时间戳,基本保持了自增。
在讲解雪花(Snowflake)算法
前,让我们先思考下面的场景:
现在的服务基本是分布式、微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性。 对于 MySQL 而言,一个表中的主键 id 一般使用自增的方式,但是如果进行水平分表之后,多个表中会生成重复的 id 值。那么如何保证水平分表后的多张表中的 id 是全局唯一性的呢?
有多种方案,如:
1、数据库主键自增
可以让不同表初始化一个不同的初始值,然后按指定的步长进行自增。例如有3张拆分表,初始主键值为1,2,3,自增步长为3。
2、UUID
用 UUID 来作为主键,但是 UUID 生成的是一个无序的字符串,对于 MySQL 推荐使用增长的数值类型值作为主键来说不适合。
3、Redis
使用 Redis 的自增原子性来生成唯一 id,但是这种方式业内比较少用。
当然还有其他解决方案,不同互联网公司也有自己内部的实现方案。雪花算法是其中一个用于解决分布式 id 的高效方案,也是许多互联网公司在推荐使用的。
优点:
优点 | 解释 |
---|---|
高性能高可用 | 生成时不依赖于数据库,完全在内存中生成 |
高吞吐 | 每秒钟能生成数百万的自增 ID |
ID 自增 | 存入数据库中,索引效率高 |
缺点:
依赖服务器时间,服务器时间回拨时可能会生成重复 id。
在获取时间的时候,可能会出现
时间回拨
的问题,什么是时间回拨问题呢?就是服务器上的时间突然倒退到之前的时间。
小小的解决方案:算法中可通过记录最后一个生成 id 时的时间戳来解决,每次生成 id 之前比较当前服务器时钟是否被回拨,避免生成重复 id。
由于时间回拨导致的生产重复的ID的问题,其实百度和美团都有自己的解决方案了,有兴趣可以去看看。
雪花结构如下图所示:
上面有说过雪花算法
会生成 64bit 的 long 型的数值,而这64bit 可以分为四个组成部分:
固定值:
1bit,最高位是符号位,0 表示正,1 表示负,固定为 0,如果是 1 就是负数了。
时间戳:
41bit,存储毫秒级时间戳(41 位的长度可以使用 69 年)。
标识位(存储机器码):
10bit,上面中的 机器id(5bit)和 服务id(5bit)统一叫作“标识位”,两个标识位组合起来最多可以支持部署 1024 个节点。
序列号:
12bit,用于表示在同一毫秒内生成的多个ID的序号。如果在同一毫秒内生成的ID超过了4096个(2的12次方),则需要等到下一毫秒再生成ID。
默认的雪花算法
是 64 bit,具体的长度可以自行配置。
如果希望运行更久,增加时间戳的位数;如果需要支持更多节点部署,增加标识位长度;如果并发很高,增加序列号位数。
总结:雪花算法
并不是一成不变的,可以根据系统内具体场景进行定制。
因为雪花算法
有序自增,保障了 MySQL 中 B+ Tree 索引结构插入高性能。
所以,日常业务使用中,雪花算法
更多是被应用在数据库的主键 ID 和业务关联主键。
假设场景:
一个订单微服务,通过
雪花算法
生成 ID,共部署三个节点,标识位一致。此时有 200 并发,均匀散布三个节点,三个节点同一毫秒同一序列号下生成 ID,那么就会产生重复 ID。
通过上述假设场景,可以知道雪花算法
生成 ID 冲突存在一定的前提条件:
解决方案:如果能保证标识位不重复,那么雪花 ID 也不会重复,有三种方案:
预分配:
应用上线前,统计当前服务的节点数,人工去申请标识位。这种方案,没有代码开发量,在服务节点固定或者项目少可以使用,但是解决不了服务节点动态扩容性问题。
动态分配:
通过将标识位存放在 Redis、Zookeeper、MySQL 等中间件,在服务启动的时候去请求标识位,请求后标识位更新为下一个可用的。
统一分配ID:
启动一个专门分配ID的服务,它来统一分配各个业务或服务需要的ID。
在雪花算法中,第一位是符号位,0表示整数,第一位如果是1则表示负数,我们用的ID默认就是正数,所以默认就是0,那么这一位默认就没有意义。
标识位一共10 bit,如果全部表示机器,那么可以表示1024台机器,如果拆分,5 bit 表示机房,5bit表示机房里面的机器,那么可以有32个机房,每个机房可以用32台机器。
Leaf 和 Uid 都有实现雪花算法
,Leaf 额外提供了号段模式生成 ID。
美团 Leaf:https://github.com/Meituan-Dianping/Leaf
百度 Uid:https://github.com/baidu/uid-generator
雪花算法 可以满足大部分场景,如无必要,不建议引入开源方案增加系统复杂度。
雪花算法
依赖于时间的一致性,如果发生时间回拨,可能会导致问题。为了解决这个问题,通常会使用拓展位来扩展时间戳的位数。原本雪花算法
只能支持69年的时间范围,但根据实际需求,可以增加时间戳的位数来延长可使用的年限,比如使用42位可以支持139年的时间范围。然而,对于很多公司来说,首要任务是生存下来,因此可能会权衡取舍,不过度追求时间戳位数的增加。
需要注意的是,雪花算法
也有一些缺点。在单机上,生成的ID是递增的,但在多台机器上,只能大致保持递增趋势,并不能严格保证递增。这是因为多台机器之间的时钟不一定完全同步。因此,在多机器环境下,对于严格的递增需求,需要考虑其他解决方案。
总而言之,雪花算法
是一种常用的分布式唯一ID生成算法,但并非完美解决方案。在使用时,需要根据实际需求和限制条件进行权衡和选择,以寻找适合自己情况的解决方案。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。