分布式唯一ID生成:雪花算法的原理及实战使用、三大问题的解决

雪花算法

一、原理

请添加图片描述

1、第1位

二进制中最高位为1的是负数,而在随机ID中,只能为正数,故该位只能为0,无意义。

2、第2位~第42位

共41bit,是当前时间戳转换为二进制而来的。可以使用69年:year = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69

3、第43位~第52位

共10bit,是当前机器(服务器)的ID,其二进制数为210即1024,所以使用雪花算法的服务最多可以同时部署在1024台服务器上。需要注意的是这里10位中的5位是给机房的,5位是给机器(服务器)的,也就是一个雪花算法服务最多能部署在25个机房,每个机房最多有2^5个机器(服务器)。

4、第53位~第64位:

共12bit,是毫秒内的序列号,即统一毫秒内生成的第几个ID,其二进制数为2^12即4096,所以同一雪花算法服务在同一毫秒内可生成4096个序列号ID,如果超出了,就只能等待下一毫秒再生成。

将以上四个部分拼接起来做位或运算,就组成了一个64位的全局唯一ID。

5、要点

1、由于时间戳是雪花算法的组成部分,所以同一服务中生成的雪花算法ID呈现递增趋势。
2、在1024台服务器的分布式系统内,不会出现ID相同的情况。
3、1毫秒产生4096个ID,那么1秒就能产生4096000个ID,可见雪花算法的效率之高。

请添加图片描述

6、缺点

  • 时间回拨问题:由于机器的时间是动态的调整的,有可能会出现时间跑到之前几毫秒,如果这个时候获取到了这种时间,则会出现数据重复。
  • 机器id分配及回收问题:目前机器id需要每台机器不一样,这样的方式分配需要有方案进行处理,同时也要考虑,如果该机器宕机了,对应的workerId分配后的回收问题。
  • 机器id上限:机器id是固定的bit,那么也就是对应的机器个数是有上限的,在有些业务场景下,需要所有机器共享同一个业务空间,那么10bit表示的1024台机器是不够的。

7、解决方案

业内的方案中对以上三个问题有这么几种处理,但是都没有彻底解决:

1.时间回拨问题

  • 采用直接抛异常方式:这种很不友好,太粗暴。
  • 采用等待跟上次时间的一段范围:这种算是简单解决,可以接受,但是如果等待一段时间后再出现回拨,则抛异常,可接受,但是不算彻底解决。

2.机器id分配及回收

  • 采用zookeeper的顺序节点分配:解决了分配,回收可采用zookeeper临时节点回收,但是临时节点不可靠,存在无故消失问题,因此也不可靠。
  • 采用DB中插入数据作为节点值:解决了分配,没有解决回收。

3.机器id上限

该问题在业内都没有处理,也就是说如果采用雪花算法,则必定会存在该问题,但是该问题也只有需要大量的业务机器共享的场景才会出现,这种情况,采用客户端 双Buffer + DB 这种非雪花算法的方案也未尝不可。

二、使用雪花算法

1、MyBatisPlus集成实现

1)、在实体类中的id上加入如下配置,指定类型为id_worker

@TableId(value = "id",type = IdType.ID_WORKER)
private Long id;

2)、在application.yml文件中配置数据中心id和机器id

mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.ctc.entity
  global-config:
    datacenter-id: 1	#数据中心(机房)ID (取值范围:0-31)
    worker-id: 1	#机器(服务器)ID (取值范围:0-31)

2、Java实现

1)编码

public class SnowflakeIdWorker {
   
 
    // ==============================Fields===========================================//
    private final long twepoch = 1420041600000L;
 
    /** 机器id所占的位数 */
    private final long workerIdBits = 5L;
 
    /** 数据标识id所占的位数 */
    private final long datacenterIdBits = 5L;
 
    /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Charte

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值