Skip to content

Commit

Permalink
Merge pull request #2 from zhongxunking/develop
Browse files Browse the repository at this point in the history
v1.5.0.RELEASE
  • Loading branch information
zhongxunking committed Apr 2, 2020
2 parents 4bb3504 + 2ead772 commit c4ef27d
Show file tree
Hide file tree
Showing 47 changed files with 1,307 additions and 671 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# idcenter
1. 简介
> 生成全局唯一的id(流水号),是很多公司都需要解决的问题。如果还是采用时间戳+随机数形式生成,在并发量大时,很有可能会生成重复的id。重复id的危害就是可能会导致一系列问题。idcenter专门用来高效的生成全局唯一id,分为服务端和客户端,每个客户端的tps可达到150万,而且服务端毫无压力
> 生成全局唯一的id(流水号),是很多公司都需要解决的问题。idcenter专门用来高效的生成全局唯一id,分为服务端和客户端。一个服务端可以支持海量的客户端请求,同时每个客户端获取id的tps可达到150万
2. 环境要求
> * 服务端:jdk1.8
Expand All @@ -15,10 +15,11 @@
<img src="https://note.youdao.com/yws/api/personal/file/WEB05da7336237569414648a5e625d2302b?method=download&shareKey=5fabc26cd1af6f5013f50dbe918c78b8" width=700 />
# 特性
idcenter具备统一的id管理能力、id具有周期概念、可承受海量获取id需求、完善的权限管理能力。
idcenter具备统一的id管理能力、id支持周期概念、可承受海量获取id需求、完善的权限管理能力。
* 统一的id管理能力:提供id管理页面,可管理公司内部所有的id。
* id具有周期概念:id的周期概念保证了id的时效性,让你看到id就知道这个id是什么时候产生的。
* 可承受海量获取id请求:客户端的预处理设计,保证了单个客户端可承受百万tps级别的id获取;并且客户端和服务端之间平均5分钟通信一次,保证了服务端可支撑大量的客户端。
* id支持周期概念:id的周期概念保证了id的时效性,让你看到id就知道这个id是什么时候产生的。
* 服务端支持海量的客户端请求:服务端的预处理设计,保证了服务端可以支持海量的客户端请求。
* 每个客户端可承受海量的id获取请求:客户端的预处理设计,保证了单个客户端可承受百万tps级别的id获取。
* 完善的权限管理能力:可对管理员的权限进行约束,让合适的人管理合适的id。

# 文档
Expand All @@ -33,7 +34,7 @@ idcenter具备统一的id管理能力、id具有周期概念、可承受海量
&ensp;&ensp;[服务端OpenAPI](https://github.com/zhongxunking/idcenter/wiki/%E6%9C%8D%E5%8A%A1%E7%AB%AFOpenAPI)

# 技术支持
欢迎加我微信入群交流。<br/>
欢迎加我微信(zhong_xun_)入群交流。<br/>
<img src="https://note.youdao.com/yws/api/personal/file/WEBbca9e0a9a6e1ea2d9ab9def1cc90f839?method=download&shareKey=00e90849ae0d3b5cb8ed7dd12bc6842e" width=200 />

# Who is using
Expand Down
2 changes: 1 addition & 1 deletion idcenter-assemble/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.antframework.idcenter</groupId>
<artifactId>idcenter</artifactId>
<version>1.4.2.RELEASE</version>
<version>1.5.0.RELEASE</version>
</parent>

<artifactId>idcenter-assemble</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion idcenter-biz/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.antframework.idcenter</groupId>
<artifactId>idcenter</artifactId>
<version>1.4.2.RELEASE</version>
<version>1.5.0.RELEASE</version>
</parent>

<artifactId>idcenter-biz</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,10 @@ public void execute(ServiceContext<AcquireIdsOrder, AcquireIdsResult> context) {
ider = iderDao.findByIderId(ider.getIderId());
log.info("被获取id的id提供者:{}", ider);
log.info("生产id前的id生产者:{}", idProducer);
// 计算生产的id数量
int amount = order.getExpectAmount();
if (ider.getMaxAmount() != null && amount > ider.getMaxAmount()) {
log.warn("期望获取id的数量[{}]过多,调整到[{}]", amount, ider.getMaxAmount());
amount = ider.getMaxAmount();
}
// 现代化id生产者
modernizeIdProducer(ider, idProducer);
// 生产id
result.setIdses(IdProducers.produce(ider, idProducer, amount));
result.setIdSegments(IdProducers.produce(ider, idProducer, order.getAmount()));
// 更新id生产者
idProducerDao.save(idProducer);
log.info("生产id后的id生产者:{}", idProducer);
Expand All @@ -90,15 +84,15 @@ private void modernizeIdProducer(Ider ider, IdProducer idProducer) {

Period period = new Period(ider.getPeriodType(), idProducer.getCurrentPeriod());
if (period.compareTo(modernPeriod) < 0) {
int modernStartId = calcModernStartId(ider, idProducer, modernPeriod);
int modernStartId = computeModernStartId(ider, idProducer, modernPeriod);
idProducer.setCurrentPeriod(modernPeriod.getDate());
idProducer.setCurrentId((long) modernStartId);
log.info("被现代化后的id生产者:{}", idProducer);
}
}

// 计算生产者跳跃到最新周期时的开始id
private int calcModernStartId(Ider ider, IdProducer idProducer, Period modernPeriod) {
private int computeModernStartId(Ider ider, IdProducer idProducer, Period modernPeriod) {
int modernStartId = (int) (idProducer.getCurrentId() % ider.getFactor());
if (ider.getMaxId() == null) {
return modernStartId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.antframework.common.util.id.Period;
import org.antframework.idcenter.dal.entity.IdProducer;
import org.antframework.idcenter.dal.entity.Ider;
import org.antframework.idcenter.facade.vo.Ids;
import org.antframework.idcenter.facade.vo.IdSegment;
import org.springframework.util.Assert;

import java.util.ArrayList;
Expand Down Expand Up @@ -54,7 +54,7 @@ public static int compare(IdProducer left, IdProducer right) {
* @param amount 需生产的id个数
* @return 生产出的id
*/
public static List<Ids> produce(Ider ider, IdProducer idProducer, int amount) {
public static List<IdSegment> produce(Ider ider, IdProducer idProducer, int amount) {
return grow(ider, idProducer, ((long) amount) * ider.getFactor());
}

Expand All @@ -66,26 +66,26 @@ public static List<Ids> produce(Ider ider, IdProducer idProducer, int amount) {
* @param length 增加长度
* @return 增加过程中产生的id
*/
public static List<Ids> grow(Ider ider, IdProducer idProducer, long length) {
public static List<IdSegment> grow(Ider ider, IdProducer idProducer, long length) {
Assert.isTrue(length >= 0, "id生产者增加长度不能小于0");
List<Ids> idses = new ArrayList<>();
List<IdSegment> idSegments = new ArrayList<>();

long newCurrentId = idProducer.getCurrentId() + length;
Assert.isTrue(newCurrentId >= idProducer.getCurrentId(), "运算中超过long类型最大值,无法进行计算");
Assert.isTrue(newCurrentId + ider.getFactor() >= newCurrentId, "运算中超过long类型最大值,无法进行计算");
long anchorId = idProducer.getCurrentId();
while (anchorId < newCurrentId) {
int idAmount = calcIdAmountOfPeriod(ider, newCurrentId, anchorId);
idses.add(buildIds(ider, idProducer, anchorId, idAmount));
int idAmount = computeIdAmountOfPeriod(ider, newCurrentId, anchorId);
idSegments.add(buildIdSegment(ider, idProducer, anchorId, idAmount));
anchorId += ((long) idAmount) * ider.getFactor();
}
updateIdProducer(idProducer, ider, newCurrentId);

return idses;
return idSegments;
}

// 计算anchorId所在周期内产生的id数量
private static int calcIdAmountOfPeriod(Ider ider, long newCurrentId, long anchorId) {
private static int computeIdAmountOfPeriod(Ider ider, long newCurrentId, long anchorId) {
long anchorEndId = newCurrentId;
if (ider.getMaxId() != null) {
long anchorMaxId = anchorId / ider.getMaxId() * ider.getMaxId() + ider.getMaxId();
Expand All @@ -95,15 +95,15 @@ private static int calcIdAmountOfPeriod(Ider ider, long newCurrentId, long ancho
return FacadeUtils.calcTotalPage(anchorEndId - anchorId, ider.getFactor());
}

// 构建批量id
private static Ids buildIds(Ider ider, IdProducer idProducer, long anchorId, int idAmount) {
// 构建id段
private static IdSegment buildIdSegment(Ider ider, IdProducer idProducer, long anchorId, int idAmount) {
Period period = new Period(ider.getPeriodType(), idProducer.getCurrentPeriod());
long startId = anchorId;
if (ider.getMaxId() != null) {
period = period.grow((int) (startId / ider.getMaxId()));
startId = startId % ider.getMaxId();
}
return new Ids(period, ider.getFactor(), startId, idAmount);
return new IdSegment(period, ider.getFactor(), startId, idAmount);
}

// 更新id生产者
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@
import org.antframework.common.util.facade.FacadeUtils;
import org.antframework.idcenter.facade.api.IderService;
import org.antframework.idcenter.facade.info.IderInfo;
import org.antframework.idcenter.facade.order.AcquireIdsOrder;
import org.antframework.idcenter.facade.order.FindIderOrder;
import org.antframework.idcenter.facade.order.ModifyIderCurrentOrder;
import org.antframework.idcenter.facade.result.AcquireIdsResult;
import org.antframework.idcenter.facade.result.FindIderResult;
import org.antframework.idcenter.facade.vo.IdSegment;

import java.util.Date;
import java.util.List;

/**
* id提供者操作类
Expand All @@ -43,6 +47,23 @@ public static void modifyIderCurrent(String iderId, Date newCurrentPeriod, Long
FacadeUtils.assertSuccess(result);
}

/**
* 获取批量id
*
* @param iderId id提供者的id(id编码)
* @param amount 数量
* @return 批量id
*/
public static List<IdSegment> acquireIds(String iderId, int amount) {
AcquireIdsOrder order = new AcquireIdsOrder();
order.setIderId(iderId);
order.setAmount(amount);

AcquireIdsResult result = IDER_SERVICE.acquireIds(order);
FacadeUtils.assertSuccess(result);
return result.getIdSegments();
}

/**
* 获取id提供者
*
Expand Down
2 changes: 1 addition & 1 deletion idcenter-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.antframework.idcenter</groupId>
<artifactId>idcenter</artifactId>
<version>1.4.2.RELEASE</version>
<version>1.5.0.RELEASE</version>
</parent>

<artifactId>idcenter-client</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,42 @@
/**
* id提供者上下文
*/
public class IdersContext {
public class IderContext {
// id提供者缓存
private final Cache<String, Ider> idersCache = new Cache<>(new Function<String, Ider>() {
private final Cache<String, Ider> iderCache = new Cache<>(new Function<String, Ider>() {
@Override
public Ider apply(String key) {
return new DefaultIder(key, minDuration, maxDuration, serverRequester);
return new DefaultIder(key, minDuration, maxDuration, maxBlockedThreads, serverRequester);
}
});
// 最小预留时间(毫秒)
private final long minDuration;
// 最大预留时间(毫秒)
private final long maxDuration;
// 最多被阻塞的线程数量
private final Integer maxBlockedThreads;
// 服务端请求器
private final ServerRequester serverRequester;

/**
* 构造id提供者上下文
*
* @param serverUrl 服务端地址
* @param minDuration 最小预留时间(毫秒)
* @param maxDuration 最大预留时间(毫秒)
* @param serverUrl 服务端地址
* @param minDuration 最小预留时间(毫秒)
* @param maxDuration 最大预留时间(毫秒)
* @param maxBlockedThreads 最多被阻塞的线程数量(null表示不限制数量)
*/
public IdersContext(String serverUrl, long minDuration, long maxDuration) {
if (StringUtils.isBlank(serverUrl) || minDuration < 0 || maxDuration < minDuration) {
throw new IllegalArgumentException(String.format("初始化idcenter客户端的参数不合法:serverUrl=%s,minDuration=%d,maxDuration=%d", serverUrl, minDuration, maxDuration));
public IderContext(String serverUrl, long minDuration, long maxDuration, Integer maxBlockedThreads) {
if (StringUtils.isBlank(serverUrl)
|| minDuration < 0
|| maxDuration < minDuration
|| (maxBlockedThreads != null && maxBlockedThreads < 0)) {
throw new IllegalArgumentException(String.format("初始化IderContext的参数不合法:serverUrl=%s,minDuration=%d,maxDuration=%d,maxBlockedThreads=%s", serverUrl, minDuration, maxDuration, maxBlockedThreads));
}
this.minDuration = minDuration;
this.maxDuration = maxDuration;
serverRequester = new ServerRequester(serverUrl);
this.maxBlockedThreads = maxBlockedThreads;
this.serverRequester = new ServerRequester(serverUrl);
}

/**
Expand All @@ -56,6 +63,6 @@ public IdersContext(String serverUrl, long minDuration, long maxDuration) {
* @return id提供者
*/
public Ider getIder(String iderId) {
return idersCache.get(iderId);
return iderCache.get(iderId);
}
}
Loading

0 comments on commit c4ef27d

Please sign in to comment.