Commit 7e7aa7cc authored by zhiguo.liu's avatar zhiguo.liu

# 修改新发号器为使用时无需注入

parent da4e5345
......@@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit;
* uid-generator 通过对 64 位数字分区来生成唯一 ID,由以下组成:
* <p>
* -----------------------------------------------------------------------------------
* | sign | delta seconds | worker id | sequence
* | sign | delta seconds | worker id | SEQUENCE
* -----------------------------------------------------------------------------------
* 1bits 28bits 22bits 13bits
* -----------------------------------------------------------------------------------
......@@ -45,14 +45,14 @@ import java.util.concurrent.TimeUnit;
* 经测试,BigInteger 实现时,性能降低 60% 左右,每秒发号约为 100w~150w。
* 现在 uid 由以下组成
* ---------------------------------------------------------------------------------------------------------
* | sign(length < 64) | delta seconds (unlimited) | data center id | worker id | sequence
* | sign(length < 64) | delta seconds (unlimited) | data center id | worker id | SEQUENCE
* ---------------------------------------------------------------------------------------------------------
* 1bits 28bits 22bits 22bits 13bits
* ---------------------------------------------------------------------------------------------------------
* 其中 data center id + worker id + sequence 设定的位数不大于 63。
* 其中 data center id + worker id + SEQUENCE 设定的位数不大于 63。
* <p>
* 使用注意:
* 1. 号码的位数不固定,会随着时间增长。data center id + worker id + sequence 总数设定越大,号码位数越长
* 1. 号码的位数不固定,会随着时间增长。data center id + worker id + SEQUENCE 总数设定越大,号码位数越长
* 2. 各个分区的位数、起始时间一旦设定完成投入使用,则后续不能更改。否则会导致发号重复。
*
* @author zhiguo.liu
......@@ -71,27 +71,27 @@ public class IDGenerator implements InitializingBean {
*/
@Value("${id.dataCenterIdBits:0}")
protected int dataCenterIdBits;
@Value("${id.workerBits:8}")
protected int workerBits;
@Value("${id.seqBits:13}")
protected int seqBits;
@Value("${data.center.id}")
protected long dataCenterId;
@Value("${id.workerBits:8}")
protected int workerBits;
protected static long DATA_CENTER_ID;
/**
* Customer epoch, unit as second. For example 2018-03-01 (ms: 1463673600000)
*/
protected String epochStr;
protected long epochSeconds;
private static long EPOCH_SECONDS;
/**
* Stable fields after spring bean initializing
*/
protected BitsAllocator bitsAllocator;
protected long workerId;
private static BitsAllocator ALLOCATOR;
private static long WORKER_ID;
/**
* Volatile fields caused by nextId()
*/
protected long sequence = 0L;
protected long lastSecond = -1L;
private static long SEQUENCE = 0L;
private static long LAST_SECOND = -1L;
/**
* Spring property
*/
......@@ -102,18 +102,18 @@ public class IDGenerator implements InitializingBean {
public void afterPropertiesSet() throws Exception {
// initialize bits allocator
int timeBits = 64 - 1 - dataCenterIdBits - workerBits - seqBits;
bitsAllocator = new BitsAllocator(timeBits, dataCenterIdBits, workerBits, seqBits);
ALLOCATOR = new BitsAllocator(timeBits, dataCenterIdBits, workerBits, seqBits);
// initialize worker id
workerId = redisTemplate.opsForValue().increment(REDIS_WORK_ID_KEY + dataCenterId, 1) % bitsAllocator.getMaxWorkerId();
Assert.isTrue(workerId < bitsAllocator.getMaxWorkerId(), "workerId is too big");
Assert.isTrue(bitsAllocator.getMaxDataCenterId() != 0 && dataCenterId < bitsAllocator.getMaxDataCenterId(), "dataCenterId is too big");
WORKER_ID = redisTemplate.opsForValue().increment(REDIS_WORK_ID_KEY + DATA_CENTER_ID, 1) % ALLOCATOR.getMaxWorkerId();
Assert.isTrue(WORKER_ID < ALLOCATOR.getMaxWorkerId(), "WORKER_ID is too big");
Assert.isTrue(ALLOCATOR.getMaxDataCenterId() != 0 && DATA_CENTER_ID < ALLOCATOR.getMaxDataCenterId(), "DATA_CENTER_ID is too big");
LOGGER.info("Initialized bits dataCenterBits:{}, workerBits:{}, seqBits:{}", dataCenterIdBits, workerBits, seqBits);
LOGGER.info("Initialized nodes, workerId:{}, dataCenterId:{}", workerId, dataCenterId);
LOGGER.info("Initialized nodes, WORKER_ID:{}, DATA_CENTER_ID:{}", WORKER_ID, DATA_CENTER_ID);
}
public String getID(String preFix) throws IDGenerateException {
public String getID(String prefix) throws IDGenerateException {
try {
return nextId(preFix);
return nextId(prefix);
} catch (Exception e) {
LOGGER.error("Generate unique id exception. ", e);
throw new IDGenerateException(e);
......@@ -124,9 +124,9 @@ public class IDGenerator implements InitializingBean {
BigInteger bigInteger = new BigInteger(idStr);
int totalBits = bigInteger.bitLength();
long dataCenterIdBits = bitsAllocator.getDataCenterIdBits();
long workerIdBits = bitsAllocator.getWorkerIdBits();
long sequenceBits = bitsAllocator.getSequenceBits();
long dataCenterIdBits = ALLOCATOR.getDataCenterIdBits();
long workerIdBits = ALLOCATOR.getWorkerIdBits();
long sequenceBits = ALLOCATOR.getSequenceBits();
if (totalBits < 64) {
totalBits = 64;
long id = bigInteger.longValue();
......@@ -137,9 +137,9 @@ public class IDGenerator implements InitializingBean {
dataCenterId = 0;
}
long deltaSeconds = id >>> (dataCenterIdBits + workerIdBits + sequenceBits);
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(EPOCH_SECONDS + deltaSeconds));
String thatTimeStr = DateFormatUtils.format(thatTime, DATETIME_PATTERN);
return String.format("{\"ID\":\"%d\",\"timestamp\":\"%s\",\"dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
return String.format("{\"ID\":\"%d\",\"timestamp\":\"%s\",\"DATA_CENTER_ID\":\"%d\",\"WORKER_ID\":\"%d\",\"SEQUENCE\":\"%d\"}",
id, thatTimeStr, dataCenterId, workerId, sequence);
} else {
long sequence = getBigIntegerFromLength(sequenceBits).and(bigInteger).longValue();
......@@ -149,9 +149,9 @@ public class IDGenerator implements InitializingBean {
dataCenterId = 0;
}
long deltaSeconds = bigInteger.shiftRight((int) dataCenterIdBits + (int) workerIdBits + (int) sequenceBits).longValue();
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(EPOCH_SECONDS + deltaSeconds));
String thatTimeStr = DateFormatUtils.format(thatTime, DATETIME_PATTERN);
return String.format("{\"ID\":\"%d\",\"timestamp\":\"%s\",\"dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
return String.format("{\"ID\":\"%d\",\"timestamp\":\"%s\",\"DATA_CENTER_ID\":\"%d\",\"WORKER_ID\":\"%d\",\"SEQUENCE\":\"%d\"}",
bigInteger, thatTimeStr, dataCenterId, workerId, sequence);
}
}
......@@ -170,29 +170,29 @@ public class IDGenerator implements InitializingBean {
long currentSecond = getCurrentSecond();
// Clock moved backwards, wait for newest time
if (currentSecond < lastSecond) {
getNextSecond(lastSecond);
if (currentSecond < LAST_SECOND) {
getNextSecond(LAST_SECOND);
}
// At the same second, increase sequence
if (currentSecond == lastSecond) {
sequence = (sequence + 1) & bitsAllocator.getMaxSequence();
// Exceed the max sequence, we wait the next second to generate ID
if (sequence == 0) {
currentSecond = getNextSecond(lastSecond);
// At the same second, increase SEQUENCE
if (currentSecond == LAST_SECOND) {
SEQUENCE = (SEQUENCE + 1) & ALLOCATOR.getMaxSequence();
// Exceed the max SEQUENCE, we wait the next second to generate ID
if (SEQUENCE == 0) {
currentSecond = getNextSecond(LAST_SECOND);
}
// At the different second, sequence restart from zero
// At the different second, SEQUENCE restart from zero
} else {
sequence = 0L;
SEQUENCE = 0L;
}
lastSecond = currentSecond;
LAST_SECOND = currentSecond;
// 当前时间小于设定的最大时间,即总位数在 64 位以下,用 long 生成数字
if (currentSecond - epochSeconds <= bitsAllocator.getMaxDeltaSeconds()) {
return preFix + bitsAllocator.allocate(currentSecond - epochSeconds, dataCenterId, workerId, sequence);
if (currentSecond - EPOCH_SECONDS <= ALLOCATOR.getMaxDeltaSeconds()) {
return preFix + ALLOCATOR.allocate(currentSecond - EPOCH_SECONDS, DATA_CENTER_ID, WORKER_ID, SEQUENCE);
}
return preFix + bitsAllocator.allocateBigInteger(currentSecond - epochSeconds, dataCenterId, workerId, sequence);
return preFix + ALLOCATOR.allocateBigInteger(currentSecond - EPOCH_SECONDS, DATA_CENTER_ID, WORKER_ID, SEQUENCE);
}
/**
......@@ -214,16 +214,9 @@ public class IDGenerator implements InitializingBean {
return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
}
public void setWorkerBits(int workerBits) {
if (workerBits > 0) {
this.workerBits = workerBits;
}
}
public void setSeqBits(int seqBits) {
if (seqBits > 0) {
this.seqBits = seqBits;
}
@Value("${data.center.id}")
public void setDataCenterId(Integer dataCenterId) {
DATA_CENTER_ID = dataCenterId;
}
@Value("${id.epochStr:2018-04-01}")
......@@ -231,7 +224,7 @@ public class IDGenerator implements InitializingBean {
if (StringUtils.isNotBlank(epochStr)) {
this.epochStr = epochStr;
try {
this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(DateUtils.parseDate(epochStr, new String[]{DAY_PATTERN}).getTime());
EPOCH_SECONDS = TimeUnit.MILLISECONDS.toSeconds(DateUtils.parseDate(epochStr, new String[]{DAY_PATTERN}).getTime());
} catch (ParseException e) {
e.printStackTrace();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment