### 一、设计背景与核心诉求¶
优惠券 ID 需解决两大核心问题:
-
安全性:避免 ID 规律性导致敏感信息泄露(如订单量)、恶意猜测薅券;
-
分布式唯一性:支撑秒杀高并发场景,适配拆库拆表后的全局唯一标识需求;
-
兼顾高性能、高可用(无锁设计)。
二、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")隔离。
三、核心优势(贴合业务场景)¶
-
唯一性保障:
-
时间戳偏移 + Redis 日级自增:同一秒内通过 32 位序列号去重,分布式环境无需锁,性能极高;
-
按业务前缀区分:避免优惠券 ID 与订单 ID 等其他业务 ID 冲突。
-
安全性优化:
-
非连续自增:时间戳偏移 + 随机增长的序列号,无法通过 “ID+1” 猜测未发放优惠券,阻断薅券风险;
-
无规律可循:ID 不直接暴露发放时间、数量等敏感信息。
-
高可用与扩展性:
-
Redis 集群部署:支持故障转移,确保 ID 生成不中断;
-
适配秒杀场景:每秒 2³² 个 ID 的生成能力,完全满足大促高并发发放需求;
-
兼容拆库拆表:全局唯一标识,无需担心分表后 ID 重复。
-
轻量化实现:
-
无复杂编码规则:通过位运算直接拼接,生成效率高,存储成本低(Long 型仅 8 字节);
-
运维友好:Redis 自增无需手动维护计数器,日级 key 自动隔离历史数据。
四、与传统方案对比¶
| 方案 | 劣势 | 本方案优势 |
| 数据库自增 ID | 规律明显、分布式需锁、分表冲突 | 无规律、无锁、全局唯一 |
| 纯随机串 | 需去重、无可读性、性能低 | 无需去重、生成效率高 |
五、总结¶
该方案基于 Redis 实现,以 “轻量化、高并发、高安全” 为核心,完美适配优惠券秒杀场景的分布式、高并发、防薅券需求,同时预留了足够的扩展空间(如新增业务维度可调整 keyPrefix),是兼顾实用性与性价比的最优解。