Commit 6ac83088 authored by zhiguo.liu's avatar zhiguo.liu

# 精简新发号器结构,修改旧新发号器名称为 OIDGenerator。

parent 74a67b85
......@@ -35,7 +35,7 @@ import java.util.concurrent.locks.ReentrantLock;
@Component
@ConditionalOnClass(RedisTemplate.class)
@ConditionalOnProperty(name = "data.center.id")
public class IDGenerator {
public class OIDGenerator {
private static final String REDIS_WORK_ID_KEY = "GLOBAL:WORK:ID:";
private static final String ID_FORMAT = "yyyyMMddHHmmss";
......
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.quantgroup.tech.util.id;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@Component
@ConditionalOnClass(RedisTemplate.class)
public class DisposableWorkerIdAssigner {
private static final Logger LOGGER = LoggerFactory.getLogger(DisposableWorkerIdAssigner.class);
private static final String REDIS_WORK_ID_KEY = "GLOBAL:WORK:ID:";
@Autowired
private StringRedisTemplate redisTemplate;
/**
* Assign worker id base on Redis.<p>
* 使用 Redis 的 incr 命令,最后结果为 incr % maxWorkerId
* @param dataCenterId
* @param bitsAllocator
* @return assigned worker id
*/
public long assignWorkerId(long dataCenterId, BitsAllocator bitsAllocator) {
return redisTemplate.opsForValue().increment(REDIS_WORK_ID_KEY + dataCenterId, 1) % bitsAllocator.getMaxWorkerId();
}
}
......@@ -16,11 +16,9 @@
package cn.quantgroup.tech.util.id;
/**
* UidGenerateException
*
* @author yutianbao
* IDGenerateException
*/
public class UidGenerateException extends RuntimeException {
public class IDGenerateException extends RuntimeException {
/**
* Serial Version UID
......@@ -30,45 +28,16 @@ public class UidGenerateException extends RuntimeException {
/**
* Default constructor
*/
public UidGenerateException() {
public IDGenerateException() {
super();
}
/**
* Constructor with message & cause
*
* @param message
* @param cause
*/
public UidGenerateException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructor with message
*
* @param message
*/
public UidGenerateException(String message) {
super(message);
}
/**
* Constructor with message format
*
* @param msgFormat
* @param args
*/
public UidGenerateException(String msgFormat, Object... args) {
super(String.format(msgFormat, args));
}
/**
* Constructor with cause
*
* @param cause
*/
public UidGenerateException(Throwable cause) {
public IDGenerateException(Throwable cause) {
super(cause);
}
......
......@@ -8,7 +8,10 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
......@@ -18,7 +21,7 @@ import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Represents an implementation of {@link UidGenerator}
* Represents an implementation of {@link IDGenerator}
* 基于百度开源项目 uid-generator 的增强版,Snowflake Java 实现版本。项目 Github:https://github.com/baidu/uid-generator
* <p>
* uid-generator 通过对 64 位数字分区来生成唯一 ID,由以下组成:
......@@ -55,47 +58,45 @@ import java.util.concurrent.TimeUnit;
* @author zhiguo.liu
*/
@Component
@ConditionalOnProperty(name = "data.center.id")
public class DefaultUidGenerator implements UidGenerator, InitializingBean {
public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DAY_PATTERN = "yyyy-MM-dd";
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultUidGenerator.class);
@ConditionalOnClass(RedisTemplate.class)
@ConditionalOnProperty(name = "id.epochStr")
public class IDGenerator implements InitializingBean {
private static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
private static final String DAY_PATTERN = "yyyy-MM-dd";
private static final Logger LOGGER = LoggerFactory.getLogger(IDGenerator.class);
private static final String REDIS_WORK_ID_KEY = "GLOBAL:WORK:ID:";
/**
* Bits allocate
*/
@Value("${uid.dataCenterIdBits:9}")
@Value("${id.dataCenterIdBits:9}")
protected int dataCenterIdBits;
@Value("${uid.workerBits:13}")
@Value("${id.workerBits:13}")
protected int workerBits;
@Value("${uid.seqBits:13}")
@Value("${id.seqBits:13}")
protected int seqBits;
@Value("${data.center.id}")
protected long dataCenterId;
/**
* Customer epoch, unit as second. For example 2018-03-01 (ms: 1463673600000)
*/
protected String epochStr;
protected long epochSeconds;
/**
* Stable fields after spring bean initializing
*/
protected BitsAllocator bitsAllocator;
protected long workerId;
/**
* Volatile fields caused by nextId()
*/
protected long sequence = 0L;
protected long lastSecond = -1L;
/**
* Spring property
*/
@Autowired
protected DisposableWorkerIdAssigner workerIdAssigner;
private StringRedisTemplate redisTemplate;
@Override
public void afterPropertiesSet() throws Exception {
......@@ -103,26 +104,24 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
int timeBits = 64 - 1 - dataCenterIdBits - workerBits - seqBits;
bitsAllocator = new BitsAllocator(timeBits, dataCenterIdBits, workerBits, seqBits);
// initialize worker id
workerId = workerIdAssigner.assignWorkerId(dataCenterId, bitsAllocator);
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");
LOGGER.info("Initialized bits dataCenterBits:{}, workerBits:{}, seqBits:{}", dataCenterIdBits, workerBits, seqBits);
LOGGER.info("Initialized nodes, workerId:{}, dataCenterId:{}", workerId, dataCenterId);
}
@Override
public String getUID(String preFix) throws UidGenerateException {
public String getID(String preFix) throws IDGenerateException {
try {
return nextId(preFix);
} catch (Exception e) {
LOGGER.error("Generate unique id exception. ", e);
throw new UidGenerateException(e);
throw new IDGenerateException(e);
}
}
@Override
public String parseUID(String uidStr) {
BigInteger bigInteger = new BigInteger(uidStr);
public String parseID(String idStr) {
BigInteger bigInteger = new BigInteger(idStr);
int totalBits = bigInteger.bitLength();
long dataCenterIdBits = bitsAllocator.getDataCenterIdBits();
......@@ -130,18 +129,18 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
long sequenceBits = bitsAllocator.getSequenceBits();
if (totalBits < 64) {
totalBits = 64;
long uid = bigInteger.longValue();
long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
long workerId = (uid << (totalBits - workerIdBits - sequenceBits)) >>> (totalBits - workerIdBits);
long dataCenterId = (uid << (totalBits - dataCenterIdBits - workerIdBits - sequenceBits)) >>> (totalBits - dataCenterIdBits);
long id = bigInteger.longValue();
long sequence = (id << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
long workerId = (id << (totalBits - workerIdBits - sequenceBits)) >>> (totalBits - workerIdBits);
long dataCenterId = (id << (totalBits - dataCenterIdBits - workerIdBits - sequenceBits)) >>> (totalBits - dataCenterIdBits);
if (dataCenterIdBits == 0) {
dataCenterId = 0;
}
long deltaSeconds = uid >>> (dataCenterIdBits + workerIdBits + sequenceBits);
long deltaSeconds = id >>> (dataCenterIdBits + workerIdBits + sequenceBits);
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
String thatTimeStr = DateFormatUtils.format(thatTime, DATETIME_PATTERN);
return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
uid, thatTimeStr, dataCenterId, workerId, sequence);
return String.format("{\"ID\":\"%d\",\"timestamp\":\"%s\",\"dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
id, thatTimeStr, dataCenterId, workerId, sequence);
} else {
long sequence = getBigIntegerFromLength(sequenceBits).and(bigInteger).longValue();
long workerId = getBigIntegerFromLength(workerIdBits).and(bigInteger.shiftRight((int) sequenceBits)).longValue();
......@@ -152,7 +151,7 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
long deltaSeconds = bigInteger.shiftRight((int) dataCenterIdBits + (int) workerIdBits + (int) sequenceBits).longValue();
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
String thatTimeStr = DateFormatUtils.format(thatTime, DATETIME_PATTERN);
return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
return String.format("{\"ID\":\"%d\",\"timestamp\":\"%s\",\"dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
bigInteger, thatTimeStr, dataCenterId, workerId, sequence);
}
}
......@@ -162,10 +161,10 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
}
/**
* Get UID
* Get ID
*
* @return UID
* @throws UidGenerateException in the case: Clock moved backwards; Exceeds the max timestamp
* @return ID
* @throws IDGenerateException in the case: Clock moved backwards; Exceeds the max timestamp
*/
protected synchronized String nextId(String preFix) {
long currentSecond = getCurrentSecond();
......@@ -178,7 +177,7 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
// 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 uid
// Exceed the max sequence, we wait the next second to generate ID
if (sequence == 0) {
currentSecond = getNextSecond(lastSecond);
}
......@@ -227,7 +226,7 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
}
}
@Value("${uid.epochStr:2018-03-01}")
@Value("${id.epochStr:2018-03-01}")
public void setEpochStr(String epochStr) {
if (StringUtils.isNotBlank(epochStr)) {
this.epochStr = epochStr;
......
package cn.quantgroup.tech.util.id;
/**
* Represents a unique id generator.
*
* @author yutianbao
*/
public interface UidGenerator {
/**
* Get a unique ID
*
* @return UID
* @throws UidGenerateException
*/
String getUID(String preFix) throws UidGenerateException;
/**
* Parse the UID into elements which are used to generate the UID. <br>
* Such as timestamp & workerId & sequence...
*
* @param uid
* @return Parsed info
*/
String parseUID(String uid);
}
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