Redis - 全局ID生成器 RedisIdWorker
文章目录
- Redis - 全局ID生成器 RedisIdWorker
- 一、引言
- 二、实现原理
- 三、代码实现
- 代码说明
- 四、使用示例
- 示例说明
- 五、总结
Redis - 全局ID生成器 RedisIdWorker
一、引言
在分布式系统中,生成全局唯一ID是一个常见的需求。传统的自增ID生成方式在分布式环境下容易出现冲突,而UUID虽然可以保证唯一性,但长度较长且不够紧凑。RedisIdWorker是一种基于Redis实现的全局ID生成器,它结合了时间戳和自增序列号,能够在分布式环境中高效地生成唯一且有序的ID。
二、实现原理
RedisIdWorker的核心思想是利用Redis的自增特性和时间戳来生成唯一且有序的ID。其生成的ID由两部分组成:
- 时间戳部分:使用当前时间戳减去一个起始时间戳(例如某个特定日期的时间戳),得到一个相对时间戳。时间戳部分通常占用31位,以秒为单位,这样可以保证在69年内生成的ID是唯一的。
- 自增序列号部分:使用Redis的
INCR
命令生成一个自增序列号,确保在相同的时间戳下,ID是唯一的。序列号部分通常占用32位,这意味着每秒可以生成2^32个不同的ID。
在具体实现中,时间戳部分和自增序列号部分通过位运算组合在一起。时间戳部分左移32位,然后与序列号部分进行按位或操作,最终生成一个64位的全局唯一ID。这种设计不仅保证了ID的唯一性,还确保了ID的递增性,有利于数据库索引的创建。
这种实现方式充分利用了Redis的原子操作特性,确保在高并发环境下生成的ID仍然是唯一的。同时,由于时间戳和序列号的结合,生成的ID具有一定的规律性,但又不会直接暴露业务逻辑。
三、代码实现
以下是RedisIdWorker的Java代码实现:
java复制
@Component
public class RedisIdWorker {
// 开始时间戳(例如2022年1月1日)
private static final long BEGIN_TIMESTAMP = 1640995200L;
// 序列号的位数
private static final int COUNT_BITS = 32;
private StringRedisTemplate stringRedisTemplate;
public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
// 获取下一个自动生成的ID
public long nextId(String keyPrefix) {
// 1. 生成时间戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
// 2. 获取当前日期,用于生成key
String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
// 3. 获取自增序列号
long count = stringRedisTemplate.opsForValue().increment("incr:" + keyPrefix + ":" + date);
// 4. 拼接并返回ID
return timestamp << COUNT_BITS | count;
}
}
代码说明
- 时间戳部分:通过
LocalDateTime
获取当前时间戳,并减去起始时间戳BEGIN_TIMESTAMP
。 - 自增序列号部分:使用
StringRedisTemplate
的increment
方法,为每个日期生成一个自增序列号。 - ID拼接:将时间戳左移32位,然后与序列号进行按位或操作,生成最终的ID。
四、使用示例
以下是一个简单的使用示例:
java复制
@SpringBootTest
public class RedisIdWorkerTest {
@Resource
private RedisIdWorker redisIdWorker;
@Test
public void testIdWorker() {
// 生成订单ID
long orderId = redisIdWorker.nextId("order");
System.out.println("Generated Order ID: " + orderId);
// 生成用户ID
long userId = redisIdWorker.nextId("user");
System.out.println("Generated User ID: " + userId);
}
}
示例说明
nextId
方法接收一个keyPrefix
参数,用于区分不同类型的ID(例如订单ID、用户ID等)。- 每次调用
nextId
方法都会生成一个唯一的ID,并且由于时间戳和自增序列号的结合,生成的ID是严格递增的。
五、总结
RedisIdWorker是一种简单高效的全局ID生成器,特别适用于分布式系统。它通过结合时间戳和自增序列号,利用Redis的原子操作保证了ID的唯一性和有序性。在实际项目中,可以根据业务需求调整时间戳的起始值和序列号的位数,以满足不同的场景。
版权声明:本博客内容为原创,转载请保留原文链接及作者信息。
参考文章:
- [Redis - 全局ID生成器 RedisIdWorker - CSDN博客]
- [Redis - 全局ID生成器 RedisIdWorker本文介绍了分布式系统中的全局ID生成器RedisIdWorke - 掘金]