基于 Redis+Redisson 实现分布式高可用编码生成器

​ 在分布式系统中,编码生成是一个高频且核心的场景 ------ 订单号、流水号、设备编码、业务单据号等,都要求全局唯一、规则可配置、高性能、支持定时重置。传统的数据库自增方案存在性能瓶颈,简单的本地生成又无法保证分布式唯一性,而硬编码的规则又缺乏灵活性。

​ 本文将分享一套基于 Redis+Redisson 实现的分布式编码生成器,该方案兼顾灵活性、高性能和分布式一致性,支持自定义编码规则、分布式唯一流水号、定时重置流水号等核心能力,可直接落地到生产环境。

核心需求与设计目标

在设计编码生成器前,我们先明确核心需求:

  1. 规则灵活:支持时间(年 / 月 / 日 / 时 / 分 / 秒 / 毫秒)、自增流水号、随机字符等占位符,自定义各部分长度;
  2. 分布式唯一:多实例部署下,生成的编码必须全局唯一,无重复;
  3. 高性能:支撑高并发场景,减少数据库依赖,降低 IO 开销;
  4. 容错兜底:Redis 重启 / 清空后,流水号能从数据库恢复,避免重复;
  5. 可重置:支持按 Cron 表达式定时重置流水号(如每日零点重置为 0);
  6. 易扩展:新增占位符规则时,代码改动最小化。

核心技术栈

基础框架:Spring Boot + MyBatis-Plus(数据持久化);

分布式缓存:Redis(流水号自增、规则缓存);

分布式锁:Redisson(保证并发安全、定时任务幂等);

定时任务:ThreadPoolTaskScheduler + Cron 表达式(流水号重置);

工具类:Hutool(Cron 解析、字符串处理);

性能优化:本地缓存 + Redis 缓存、异步批量持久化。

核心功能与实现原理

编码规则设计

编码规则采用 "固定字符 + 占位符" 的形式,支持以下占位符(可自定义扩展):

占位符 含义 示例(长度 4)
${yyyy} 2026
${MM} 月(补零) 01
${dd} 日(补零) 08
${hh} 时(24 小时制) 14
${mm} 分(补零) 59
${ss} 秒(补零) 07
${S} 毫秒(补零) 123(最大 3 位)
${X} 自增流水号 0001、00002
${UUU} 随机字符 A87、9z6

示例规则:JPC${hh}${UUU}${mm}${ss}${XXXX} → 生成结果:JPC14A8759070001

核心模块实现

规则解析模块

规则解析是编码生成的基础,核心逻辑通过栈结构 解析占位符,提取占位符类型和长度,代码核心逻辑在parseCodeRulegenerateConfigValue方法中:

  • 遍历规则字符串,通过栈匹配${}边界,提取内部的占位符(如XXXX);
  • 校验占位符合法性(必须是连续相同字符,如XXXX而非XxXX);
  • 根据占位符类型(如X= 流水号、U= 随机数)生成对应内容,补零或截取到指定长度。

核心亮点:解析逻辑与生成逻辑解耦,新增占位符只需在generateConfigValue的 switch 中添加分支,扩展性极强。

分布式流水号生成(核心)

流水号是编码唯一性的关键,采用 "Redis 自增 + 数据库兜底 + 分布式锁" 的方案:

Redis 自增 :通过redisTemplate.opsForValue().increment(seqKey, 1)实现高性能自增,Redis 的单线程特性保证自增原子性;

分布式锁防并发初始化:当 Redis 中流水号 KEY 不存在(自增返回 1)时,加 Redisson 分布式锁,从数据库查询该规则的最大流水号,初始化到 Redis,避免多实例并发初始化导致流水号重复;

数据库兜底 :Redis 重启 / 清空后,流水号从数据库max_seq字段加载,保证流水号不回退、不重复;

核心代码片段(流水号生成):

复制代码
private String generateSeqNum(CodeRule codeRule, int len) {
    String code = codeRule.getCode();
    String seqKey = REDIS_SEQ_PREFIX + code; 
    RLock initLock = redissonClient.getLock("seq:init:lock:" + code);
    try {
        Long seq = redisTemplate.opsForValue().increment(seqKey, 1);
        if (seq == 1) { // 首次初始化
            locked = initLock.tryLock(5, 10, TimeUnit.SECONDS);
            if (locked) {
                Long maxSeq = queryMaxSeqFromDb(code); // 从DB加载最大值
                if (maxSeq > 0) {
                    redisTemplate.opsForValue().set(seqKey, maxSeq);
                    seq = redisTemplate.opsForValue().increment(seqKey, 1);
                }
            }
        }
        saveBySeq(codeRule, seq); // 异步持久化
        return String.format("%0" + len + "d", seq);
    } finally {
        if (locked) initLock.unlock();
    }
}
定时重置流水号

支持按 Cron 表达式(如0 0 0 * * ?每日零点)重置流水号,核心类为SeqCronTaskManager

  1. 分布式定时任务 :基于ThreadPoolTaskScheduler创建定时任务,多实例部署下通过分布式锁保证同一时间只有一个实例执行重置;
  2. 幂等处理:通过 Redis 设置执行标识,避免同一 Cron 周期内重复重置;
  3. 统一 KEY 规则 :重置的流水号 KEY 统一为CODE_RULE_SEQ:规则标识,避免特殊字符导致的 Redis 客户端解析异常。
性能优化策略
  • 多级缓存 :编码规则先查本地缓存(CODE_RULE_CACHE),再查 Redis,最后查数据库,减少 DB 查询;
  • 异步批量持久化:流水号不是每次生成都写库,而是通过原子计数器累计到 100 次后异步批量更新,降低数据库 IO;

接口层设计

提供 RESTful 接口,支持编码规则的 CRUD、缓存刷新、编码生成等,核心生成接口:

复制代码
GET /code_rule/generateCode?code=JPC

请求示例:调用/code_rule/generateCode?code=JPC,规则为JPC${hh}${UUU}${mm}${ss}${XXXX},返回JPC14A8759070001

异常设计

异常处理
  • 分布式锁超时:抛出友好提示,避免无限阻塞;

  • Redis 类型异常:捕获 WRONGTYPE 异常,提示清理错误 KEY;

  • 空指针防护:缓存查询、数据库查询后均做非空校验;

  • 线程中断:捕获 InterruptedException,恢复线程中断状态。

redis配置

Redis 序列化配置(避免值序列化后为二进制,导致自增失败):

复制代码
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setConnectionFactory(factory);
    return template;
}
完整代码地址

https://gitee.com/zh2358853434/short-chain.git

总结

这套编码生成器方案解决了系统中编码生成的核心痛点:

  • 灵活性:通过占位符支持自定义规则,新增规则成本低;
  • 唯一性:Redis 自增 + Redisson 分布式锁保证分布式唯一;
  • 高性能:多级缓存 + 异步持久化,支撑高并发;
  • 容错性:数据库兜底 + 类型校验,避免流水号丢失或异常;
  • 可配置:Cron 表达式支持灵活的流水号重置策略。
相关推荐
倔强的石头_14 小时前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
jiayou642 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤3 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
初次攀爬者4 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
爱可生开源社区4 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1774 天前
《从零搭建NestJS项目》
数据库·typescript
加号35 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏5 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
李慕婉学姐5 天前
Springboot智慧社区系统设计与开发6n99s526(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
百锦再5 天前
Django实现接口token检测的实现方案
数据库·python·django·sqlite·flask·fastapi·pip