我是靠谱客的博主 懦弱饼干,最近开发中收集的这篇文章主要介绍基于Redis自增函数生成分布式单号,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1. 背景

在分布式系统中,不可避免的需要协调多个服务器节点生成分布式的单号问题,如果采取单节点的方式,可能会出现单号重复的问题。从具体的实现方式而言,可以采取数据库的方案,但这个可能存在多节点同时争抢同一条数据造成死锁的问题。我们这里采取分布式中间件Redis的自增函数,实现分布式单号的生成。

2. 业务要求

分布式的单号生成组件,需要根据不同的业务要求生成不同规则的业务单号,并且在高并发的场景下保证单号唯一。

3. 分布式单号组件的实现

3.1 单号的生成业务规则接口

/**
* 分布式单号的格式化前缀接口
*/
public interface DistributedSeqNoFormat<T>{
/**
* 根据特定的业务对象类型,进行定制化的单号前缀格式化输出
* @param t 单号的前缀格式化操作对象
* @return 单号的前缀
* @author chenyz18
*/
String format(T t);
}

3.2 单号生成器

/**
* 分布式单号生成器
*
*/
public class DistributedSeqNoGenerator <T>{
private static final Logger logger = LoggerFactory.getLogger(DistributedSeqNoGenerator.class);
/**
* 根据业务定制化的前缀格式化生成器,生成分布式的业务单号
* @param format 格式化生成器的实现实例
* @param expiredTime 单号的前缀超时时间, 如果设置为-1则不会超时
* @param t 格式化生成器的格式化业务操作类型实例对象
//* @param <T> 格式化生成器的格式化业务操作类型
* @return 分布式的单号
*/
public String getBizSerialNo(DistributedSeqNoFormat<T> format, T t, Long expiredTime) {
StringBuilder serialNo = new StringBuilder();
String prefix = format.format(t);
serialNo.append(prefix);
serialNo.append(getCommonSerialNo(prefix, expiredTime));
return serialNo.toString();
}
/**
* 根据业务定制化的前缀格式化生成器,生成定长的分布式业务单号
* @param format 格式化生成器的实现实例
* @param t 格式化生成器的格式化业务操作类型实例对象
* @param maxSerialNo 序列化的对打长度,如果生成的序列号不足该长度,则补零
* @param expiredTime 单号的前缀超时时间, 如果设置为-1则不会超时
//* @param <T> 格式化生成器的格式化业务操作类型
* @return 分布式的单号
*/
public
String getFixedLengthBizSerialNo(DistributedSeqNoFormat<T> format, T t, Integer maxSerialNo, Long expiredTime) {
String prefix = format.format(t);
Long seqNo = getCommonSerialNo(prefix, expiredTime);
int startNoLen = Long.toString(seqNo).length();
if (startNoLen <= maxSerialNo) {
String tmpStr = "";
//空缺的为止用0补全
for (int i = 0; i < (maxSerialNo - startNoLen); i++) {
tmpStr = tmpStr + "0";
}
String serialNo = tmpStr + seqNo;
serialNo = prefix + serialNo;
return serialNo;
} else {
return getFixedLengthBizSerialNo(format, t, maxSerialNo, expiredTime);
}
}
/**
* 根据redis生成分布式的序列号
*
* @param prefix
序列号前缀
* @param expiredTime 序列号的过期时间
* @return 根据序列号前缀生成的序列号
*/
public static Long getCommonSerialNo(String prefix, Long expiredTime) {
if (StringUtils.isBlank(prefix)) {
throw new IllegalArgumentException("单号前缀不能为空!");
}
long resultSeq;
//get redis client implements instantce 
CodisImpl cache = (CodisImpl) SpringUtil.getBean("redisBean");
resultSeq = cache.incr(prefix);
if (expiredTime > 0) {
cache.expire(prefix, expiredTime);
}
return resultSeq;
}
}

3.3测试类

	public static String getBillNO( String prefix){
DistributedSeqNoGenerator<String> generator = new DistributedSeqNoGenerator<>();
return generator.getFixedLengthBizSerialNo(new DistributedSeqNoFormat<String>() {
@Override
public String format(String s) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
String str = dateFormat.format(new Date());
return s+str;
}
},prefix, maxSeriaNo,86400L);
}

实际测试,单秒的并发量维持在8500+的水平,不同的业务场景,可以根据DistributedSeqNoFormat并使用泛型对象来组装不同的业务单号前缀,指定单号的长度,从而满足不同的业务需求。

最后

以上就是懦弱饼干为你收集整理的基于Redis自增函数生成分布式单号的全部内容,希望文章能够帮你解决基于Redis自增函数生成分布式单号所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部