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

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

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