分布式id之雪花算法 -- SnowFlake

​​​​​​

简介
Snowflake 是 Twitter 开源的分布式 ID 生成算法,目的是在分布式系统中生成全局唯一且趋势递增的 long(64bit) 的id数值。
其特性是各节点无需协调、按时间大致有序、且整个集群各节点单不重复。
该数值的默认组成如下(符号位之外的三部分允许个性化调整):
1bit: 符号位,始终是 0(为了保证主键是正数)。
41bit: 毫秒数(可用 69 年);
10bit: 节点ID(5bit数据中心 + 5bit节点ID,支持 32 * 32 = 1024 个节点)
12bit: 流水号(每个节点每毫秒内支持 4096 个 ID,相当于 409万的 QPS)
整个64位数值最大值为2的63次方-1,正好等于Long.MAX_VALUE(9223372036854775807)
在这里插入图片描述

在认识雪花算法前,我们过去通常有两种生成全局唯一id的方式
一、UUID
UUID是通过唯一识别码,可以生成一个长度32位的全局唯一识别码。
String uuid = UUID.randomUUID().toString();
缺点:UUID虽然能保证全局唯一,但是占用32位有些太长,而且是无序的,入库时性能较差。(由于关系型数据库索引大多都是B+ tree结构,每个索引节点都存储着若干个id,如果无序的插入会导致一些中间节点分裂,造成很多节点不饱和,大大降低了数据库插入性能)

二、数据库自增主键
分布式系统中用DB proxy请求不同的分库,每个分库设置不同的初始值,步长和分库数量相等:
在这里插入图片描述
缺点:id的生成严重依赖数据库,不但影响性能,而且一旦数据库宕机,服务将变得不可用。

三、SnowFlake算法
最后就是我们的主角登场了,雪花算法支持毫秒级的百万id生成操作。
代码编写很简单,首先定义一个初始时间戳startTimestamp(41位),比如1483200000000L(2017-01-01),接着获取相应的机房和机器id码(10位),当然这些都可以根据业务自己调整,我目前做的项目就是12位的机器id码+10位的sequence序列号
1、同步锁保证线程安全,step1中,我们先比较当前时间戳与上次缓存毫秒时间,如果小于缓存时间(两种原因,一是毫秒级sequence达到了上限,二是时间回调),则使用上次缓存毫秒时间戳进行缓存计数器计数操作
2、step2中,我们判断当前时间戳与上次缓存时间是否相等,若相等则进行缓存计数器sequence+1操作,当sequence达到最大值2的10次方1024时,重置为0,且当前时间戳+1;若不等,即当前时间戳大于缓存时间戳,那么sequence从0开始新的计数
3、step3中将当前时间戳的值缓存到lastTimestamp,进行二进制的位运算获得64位全局唯一的分布式id并转成十进制。
41位时间戳:(timestamp - startTimestamp) << TIMESTAMP_OFFSET,左移22位,相当于2的22次方,右边补0
10位机器码:machineId << MACHINE_OFFSET,左移12位,相当于
2的12次方,右边补0
最后将41位时间戳二进制值、10位机器码二进制值与sequence二进制值进行或运算(相当于右边补0的位置进行相应的合并计算)
在这里插入图片描述
到这儿,大家应该也能感受到雪花算法的优点和隐患所在了,下面总结下基于雪花算法snowFlake的优缺点
优点:
1.生成ID时不依赖于DB,完全在内存生成,高性能高可用。
2.ID呈趋势递增,后续插入索引树的时候性能较好。
缺点:
依赖于系统时钟的一致性。我这边写法仅仅解决了机器系统时钟短时间内的回拨,如果某台机器的系统时钟回拨+服务器重启,缓存时间丢失,那么就有可能造成ID冲突,或者ID乱序。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值