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;
}