高并发系统-分布式唯一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 详解

相关推荐
Bs_MoneyMagnet13 分钟前
基于springboot+vue的滑雪场票务与装备租赁系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
Shota Kishi4 小时前
Solana Shreds 的 UDP 直投架构:Shredstream UDP Forwarding 的设计与实现
网络协议·架构·udp·区块链·solana
AlienZHOU4 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
野生技术架构师5 小时前
2026 Java 面试全套总结,八股 + 场景 + AI 相关面试考点
java·人工智能·面试
香吧香6 小时前
java服务异常日志只打印异常类型,没有堆栈定位分析
java·jvm·异常
qq_2518364577 小时前
AI 疾病自查功能SpringbootAI项目实战 · 技术实现文档
java·ai·ai编程
狗头大军之江苏分军7 小时前
《潮水漫过十七岁》开学了
后端
逆境不可逃7 小时前
Pi Agent 学习笔记:对话太长以后,如何压缩上下文
java
MetaLite7 小时前
JDK 8~26 核心特性一览:从 Stream 到 Scoped Values
java
苏三说技术7 小时前
如何看待GPT-6在UP主众测中碾压夺冠?它是现在最强大模型吗?
后端