高并发系统-分布式唯一ID生成(三)-RedisID生成及应用

本文紧接着上文高并发系统-分布式唯一ID生成(二)-号段模式及应用

2. 生成方案

2.5 Redis ID

Redis可以作为一个可靠的存储和生成分布式ID的方案之一。 Redis分布式ID实现主要是通过提供像 INCRINCRBY 这样的自增原子命令,由于Redis单线程的特点,可以保证ID的唯一性和有序性。

1. 优点

性能不错、每秒10万并发量,性能是优于数据库。

生成的 ID 是有序递增的。

2. 缺点

redis 宕机后不可用,RDB重启数据丢失会重复ID。

自增,数据量易暴露。

引入新的组件,增加系统复杂度,并且需要占用网络资源,性能要比本地生成慢

3. 应用场景

适用于TPS要求不高场景或者可通过活动区分开,比如发放优惠券券码,可以通过批次作为前缀,每个批次使用不同REDIS自增序列

尤其比较较高并发生成唯一ID且ID长度序列一致场景,比如券码,京东E卡的卡号之类的

4. 实践

场景:生成一个10位长度券码,要求是唯一的,并且长度都为10位。

思路:

通过REDIS自增ID实现编码,序列值转换成35进制,在后面加一位Z,剩余位数用随机数填充保证固定长度唯一编码 比如序列为100,生成的最终编码为2TZB47AIPX

通过上述方式,保证生成值唯一,且能够达到35^10个

代码实现:

核心逻辑

java 复制代码
@Service
@Slf4j
public class RedisIdSeq {
    private final static char[] CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'};
    private final int SCALE = 35;
    private final static char SPLIT = 'Z';

    @Autowired
    private RedisService redisService;

    public List<String> createCode(int maxNum, int size, String priFix, String key, int maxLength) {
        int curIndex = redisService.incrAndGetIntValue(key, size);
        if (curIndex > maxNum) {
            log.error("createCode exceed max num ={}", maxNum);
            return Collections.emptyList();
        }
        List<String> resultList = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            resultList.add(generateCode(priFix, curIndex--, maxLength));
        }
        return resultList;
    }

    private String generateCode(String preFix, int num, int maxLength) {
        int temp = num;
        int index = 0;
        StringBuilder stringBuilder = new StringBuilder(maxLength);
        stringBuilder.append(preFix);
        while (temp > 0) {
            index = num % SCALE;
            stringBuilder.append(CHARS[index - 1]);
            temp = temp / SCALE;
        }
        if (stringBuilder.length() >= maxLength) {
            return stringBuilder.toString();
        }
        stringBuilder.append(SPLIT);
        int randomSize = maxLength - stringBuilder.length();
        for (int i = 0; i < randomSize; i++) {
            stringBuilder.append(CHARS[SecureRandomUtil.getInstance().nextInt(SCALE)]);
        }
        return stringBuilder.toString();
    }
}

使用redission取值

java 复制代码
public int incrAndGetIntValue(String key, Integer addNum) {
    RAtomicLong rAtomicLong = redissonClient.getAtomicLong(key);
    return (int) rAtomicLong.addAndGet(addNum);
}

最终的test用例如下

java 复制代码
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@Slf4j
public class RedisIdSeqTest {
    @Resource
    private RedisIdSeq redisIdSeq;

    @Test
    public void testCreateCode() {
        List<String> prefixList = redisIdSeq.createCode(10000, 1, "", "ABC", 10);
        log.info("prefixList={}", prefixList);
        List<String> codeList = redisIdSeq.createCode(10000, 10, prefixList.get(0), prefixList.get(0), 20);
        log.info("codeList={}", codeList);
    }
}

最终生成结果如下:

xml 复制代码
2023-12-24 21:47:28.978|INFO |test|1|127.0.0.1|8173c001efdc4303bab4aaf23464a2b8|prefixList=[1Z6PEOSSA3]|com.toby.dynamic.data.source.redis.id.RedisIdSeqTest
2023-12-24 21:47:31.552|INFO |test|1|127.0.0.1|8173c001efdc4303bab4aaf23464a2b8|codeList=[1Z6PEOSSA39Z1VC68J5P, 1Z6PEOSSA38Z468YSILR, 1Z6PEOSSA37ZAJQTERNX, 1Z6PEOSSA36Z64KRUV6A, 1Z6PEOSSA35Z9K7F06K2, 1Z6PEOSSA34ZULBTKOJ4, 1Z6PEOSSA33Z733FXM2R, 1Z6PEOSSA32ZD52WWEOC, 1Z6PEOSSA31ZAMBGCBW2, 1Z6PEOSSA30Z7BTE9SN9]|com.toby.dynamic.data.source.redis.id.RedisIdSeqTest

参考
分布式 ID 详解

相关推荐
多多*3 分钟前
计算机网络相关 讲一下rpc与传统http的区别
java·开发语言·网络·jvm·c#
源码获取_wx:Fegn08955 分钟前
计算机毕业设计|基于springboot + vue网上超市系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·spring·课程设计
屹立芯创ELEADTECH5 分钟前
CoWoS封装技术全面解析:架构、演进与AI时代的基石作用
人工智能·架构
码农水水6 分钟前
阿里Java面试被问:Online DDL的INSTANT、INPLACE、COPY算法差异
java·服务器·前端·数据库·mysql·算法·面试
Coder_Boy_7 分钟前
基于SpringAI的在线考试系统-知识点管理与试题管理模块联合回归测试文档
前端·人工智能·spring boot·架构·领域驱动
小旭95277 分钟前
【Java 基础】IO 流 全面详解
java·开发语言
Coder_Boy_10 分钟前
基于SpringAI的在线考试系统-阅卷评分与错题管理模块回归测试逻辑梳理文档
java·spring boot·系统架构·ddd·tdd·全栈开发
那起舞的日子11 分钟前
Java线程池-执行顺序
java
先做个垃圾出来………11 分钟前
Linux/Unix系统下的基础文本处理命令
java·linux·unix
风若飞12 分钟前
Linux 环境下解决 Tomcat8 与 JDK8 配置问题
java·linux·运维·服务器·tomcat