当前位置: 首页 > news >正文

使用 Redis 生成分布式唯一ID

在分布式系统中,生成唯一ID是一个常见的需求。传统的数据库自增ID无法满足分布式系统的需求,因为多个节点可能同时生成ID,容易导致冲突。本文将介绍一种使用 Redis 实现分布式唯一ID的方法,并通过代码示例进行讲解。

一、背景介绍

1.1 唯一ID的需求

在电商系统中,每个订单、用户等都需要一个唯一的标识符。这些标识符不仅需要全局唯一,还要能够快速生成。因此,我们需要一个高效、可靠的方法来生成唯一ID。

1.2 传统方法的缺陷

  • 数据库自增ID:容易成为性能瓶颈,且不适用于分布式系统。
  • UUID:虽然能保证唯一性,但不适合用作数据库主键,因为它是16进制返回的是字符串并且长度较长且不连续,影响索引性能。

二、Redis 实现分布式唯一ID

2.1 方案设计

我们可以结合时间戳和自增序列来生成唯一ID。具体方案如下:

  1. 时间戳:使用当前时间戳,保证生成的ID大致有序。
  2. 自增序列:使用 Redis 的自增(INCR)命令,保证在同一秒内生成的ID是唯一的。

最终生成的ID格式如下:

ID = 时间戳 << 序列号位数 | 序列号

2.2 代码实现

下面是具体的代码实现:

@Component
public class RedisIdWorker {private static final long BEGIN_TIMESTAMP = 1704067200L;private static final int COUNT_BITS = 32;private StringRedisTemplate stringRedisTemplate;public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}public long nextId(String keyPrefix) {// 1.生成时间戳LocalDateTime now = LocalDateTime.now();long nowSecond = now.toEpochSecond(ZoneOffset.UTC);long timestamp = nowSecond - BEGIN_TIMESTAMP;// 2.生成序列号// 2.1获取当前日期,精确到天String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));// 2.2自增长Long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);// 3.拼接并返回return timestamp << COUNT_BITS | count;}
}

在这段代码中:

  1. 生成时间戳:通过 LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) 获取当前时间戳,并减去一个起始时间戳(BEGIN_TIMESTAMP),得到相对时间戳。
  2. 生成自增序列:通过 Redis 的 increment 方法实现每日的自增序列,保证在同一天内的ID是唯一的。
  3. 拼接ID:通过左移和按位或操作,将时间戳和自增序列拼接成最终的ID。

2.3 测试代码

为了验证我们的ID生成器是否能高效、正确地生成ID,我们可以编写以下测试代码:

@Resource
private RedisIdWorker redisIdWorker;private ExecutorService es = Executors.newFixedThreadPool(500);@Test
void testIdWorker() throws InterruptedException {CountDownLatch latch = new CountDownLatch(300);Runnable task = () -> {for (int i = 0; i < 100; i++) {long id = redisIdWorker.nextId("order");System.out.println("id = " + id);}latch.countDown();};long begin = System.currentTimeMillis();for (int i = 0; i < 300; i++) {es.submit(task);}latch.await();long end = System.currentTimeMillis();System.out.println("耗时:" + (end - begin) + "ms");
}

在这段代码中,我们使用线程池并发生成ID,并统计生成时间,验证生成ID的效率。

三、总结

通过使用 Redis,我们可以高效地生成分布式唯一ID。该方法结合了时间戳和 Redis 的自增特性,保证了ID的有序性和唯一性。同时,Redis 的高性能也保证了ID生成的效率。

相关文章:

  • python调用SDK的问题
  • 六、Nginx-正向代理和反向代理
  • 吴恩达2022机器学习专项课程C2W3:2.26 机器学习发展历程
  • 最佳websocket封装
  • java8 List的Stream流操作 (实用篇 三)
  • 【Effective Web】常见的css布局方式--三栏布局
  • 网络安全:SQL注入防范
  • 在 React 中使用 ArcGIS JavaScript SDK 构建地图应用
  • STM32高级控制定时器(STM32F103):PWM输出模式
  • 数据赋能(122)——体系:数据清洗——技术方法、主要工具
  • AWS 批量添加安全组
  • Hi3861 OpenHarmony嵌入式应用入门--点灯
  • 图像识别技术在虚拟现实与增强现实中的应用
  • 数实融合创新发展 隆道分享企业级AI应用
  • C语言:文件操作
  • 【Leetcode】101. 对称二叉树
  • JavaScript 如何正确处理 Unicode 编码问题!
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • JavaScript 基础知识 - 入门篇(一)
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • JS学习笔记——闭包
  • nginx 配置多 域名 + 多 https
  • SOFAMosn配置模型
  • Sublime text 3 3103 注册码
  • 阿里云应用高可用服务公测发布
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 聊聊directory traversal attack
  • 原生js练习题---第五课
  • 智能网联汽车信息安全
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​插件化DPI在商用WIFI中的价值
  • #define
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #Java第九次作业--输入输出流和文件操作
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (2)MFC+openGL单文档框架glFrame
  • (4)STL算法之比较
  • (9)STL算法之逆转旋转
  • (k8s)Kubernetes 从0到1容器编排之旅
  • (pojstep1.1.2)2654(直叙式模拟)
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (二)正点原子I.MX6ULL u-boot移植
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (转)ABI是什么
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .gitignore不生效的解决方案
  • .NET 8.0 发布到 IIS
  • .Net 8.0 新的变化
  • .net反混淆脱壳工具de4dot的使用
  • .NET命名规范和开发约定