Skip to content

### 一、设计背景与核心诉求

优惠券 ID 需解决两大核心问题:

  1. 安全性:避免 ID 规律性导致敏感信息泄露(如订单量)、恶意猜测薅券;

  2. 分布式唯一性:支撑秒杀高并发场景,适配拆库拆表后的全局唯一标识需求;

  3. 兼顾高性能、高可用(无锁设计)。

二、ID 结构设计(基于 Redis 实现)

采用 “分段式二进制编码”(共 64 位 Long 型),结构如下:

字段 位数 说明
符号位 1bit 固定为 0,确保 ID 为正数
时间戳偏移 31bit 当前时间戳 - 起始时间戳(2022-01-01 00:00:00),支持 69 年有效期
秒内序列号 32bit Redis 自增计数器(按日 + 业务前缀生成),每秒支持 2³² 个 ID(完全覆盖高并发)

示例与生成逻辑:

// 核心生成代码(RedisIdWorker)public long nextId(String keyPrefix) {    // 1. 计算时间戳偏移(31位)    long timeStamp = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) - 1640995200L;    // 2. 生成秒内序列号(32位):Redis按日自增,避免跨日重复    String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));    long count = stringRedisTemplate.opsForValue().increment("inc:" + keyPrefix + ":" + date);    // 3. 位运算拼接:时间戳左移32位 + 序列号(无符号拼接)    return timeStamp << 32 | count;}
  • 业务适配:生成优惠券 ID 时,keyPrefix 传入 "coupon",确保与订单 ID(keyPrefix="order")隔离。

三、核心优势(贴合业务场景)

  1. 唯一性保障

  2. 时间戳偏移 + Redis 日级自增:同一秒内通过 32 位序列号去重,分布式环境无需锁,性能极高;

  3. 按业务前缀区分:避免优惠券 ID 与订单 ID 等其他业务 ID 冲突。

  4. 安全性优化

  5. 非连续自增:时间戳偏移 + 随机增长的序列号,无法通过 “ID+1” 猜测未发放优惠券,阻断薅券风险;

  6. 无规律可循:ID 不直接暴露发放时间、数量等敏感信息。

  7. 高可用与扩展性

  8. Redis 集群部署:支持故障转移,确保 ID 生成不中断;

  9. 适配秒杀场景:每秒 2³² 个 ID 的生成能力,完全满足大促高并发发放需求;

  10. 兼容拆库拆表:全局唯一标识,无需担心分表后 ID 重复。

  11. 轻量化实现

  12. 无复杂编码规则:通过位运算直接拼接,生成效率高,存储成本低(Long 型仅 8 字节);

  13. 运维友好:Redis 自增无需手动维护计数器,日级 key 自动隔离历史数据。

四、与传统方案对比

方案 劣势 本方案优势
数据库自增 ID 规律明显、分布式需锁、分表冲突 无规律、无锁、全局唯一
纯随机串 需去重、无可读性、性能低 无需去重、生成效率高

五、总结

该方案基于 Redis 实现,以 “轻量化、高并发、高安全” 为核心,完美适配优惠券秒杀场景的分布式、高并发、防薅券需求,同时预留了足够的扩展空间(如新增业务维度可调整 keyPrefix),是兼顾实用性与性价比的最优解。