百度分布式id-UidGenerator之DefaultUidGenerator源码解读

1:百度源码与图

https://github.com/baidu/uid-generator
在这里插入图片描述

uid-generator支持自定义时间戳、工作机器id和序列号等各部分的位数,以应用于不同场景。默认分配方式如下。sign 默认一位符号标识,data seconds 时间,worder node id,机器id也是重启的次数,sequence 并发系列。uid-generator 支持两种获取id的方法,分别是DefaultUidGenerator/CachedUidGenerator.这篇先解读DefaultUidGenerator

2:DefaultUidGenerator

下载源码,在本地启动,我们可以看到default-uid-spring.xml,里面有个bean,初始化数据

1:afterPropertiesSet 初始化相关数据

    @Override
   public void afterPropertiesSet() throws Exception {
    // initialize bits allocator 初始化位移和最大值
    bitsAllocator = new BitsAllocator(timeBits, workerBits, seqBits);

    // initialize worker id 获取重启次数id
    workerId = workerIdAssigner.assignWorkerId();
    //重启id大于最大重启id次数,直接抛出异常
    if (workerId > bitsAllocator.getMaxWorkerId()) {
        throw new RuntimeException("Worker id " + workerId + " exceeds the max " + bitsAllocator.getMaxWorkerId());
    }

    LOGGER.info("Initialized bits(1, {}, {}, {}) for workerID:{}", timeBits, workerBits, seqBits, workerId);
}

1.1: bitsAllocator = new BitsAllocator(timeBits, workerBits, seqBits);

  进入这个方法,可以看到最大位移,位移数要等于64(sign+data seconds+worder node id+sequence),要不能就会抛出异常

1.2:workerId = workerIdAssigner.assignWorkerId(); 获取机器id,我们走进这方法,能够看到它在数据库增加了一条自增记录,拿到id

@Transactional
public long assignWorkerId() {
    // build worker node entity
    WorkerNodeEntity workerNodeEntity = buildWorkerNode();

    // add worker node for new (ignore the same IP + PORT)
    workerNodeDAO.addWorkerNode(workerNodeEntity);
    LOGGER.info("Add worker node:" + workerNodeEntity);

    return workerNodeEntity.getId();
}

2: 获取id的代码

protected synchronized long nextId() {
    //获取当前时间单位s
    long currentSecond = getCurrentSecond();
    // Clock moved backwards, refuse to generate uid 当前时间大于上次时间,就意味着时间回拨,抛出去
    if (currentSecond < lastSecond) {
        long refusedSeconds = lastSecond - currentSecond;
        throw new UidGenerateException("Clock moved backwards. Refusing for %d seconds", refusedSeconds);
    }

    // At the same second, increase sequence 当前时间相等的情况下,验证是否大于最大序列值,如果大于等待下一s
    if (currentSecond == lastSecond) {
        sequence = (sequence + 1) & bitsAllocator.getMaxSequence();
        // Exceed the max sequence, we wait the next second to generate uid
        //大于就等待下一秒
        if (sequence == 0) {
            currentSecond = getNextSecond(lastSecond);
        }

    // At the different second, sequence restart from zero
    } else {
    //如果当前时间大于上一次时间,则是从0开始
        sequence = 0L;
    }

    lastSecond = currentSecond;

    // Allocate bits for UID---根据三个时间端进行位移
    return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);
}
 //获取当前最新时间s
private long getCurrentSecond() {
    long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
    //当前时间减去初始时间,还大于最大的时间位移时间,就直接抛出异常
    if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {
        throw new UidGenerateException("Timestamp bits is exhausted. Refusing UID generate. Now: " + currentSecond);
    }

    return currentSecond;
}

3 总结

3.1 DefaultUidGenerator 单位走的是s,所以最大时间是2的28次方,只够8.7年,也可以自行变更data seconds等相关参数

3.2 注意DefaultUidGenerator 时间回拨,也是强制性抛出,要解决这个还是要看CachedUidGenerator(解决了时间回拨功能)

3.3 DefaultUidGenerator 基于雪花算法稍微变更了一点,熟悉雪花算法的(看我上一篇,简单自己写雪花算法,更容易理解),非常容易入手

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值