Redis全局ID生成器的实现


Posted in Redis onJune 05, 2022

全局ID生成器,是一种在分布式系统下用来生成全局唯一ID的工具,一般满足下列特性:

  • 唯一性:确保ID是唯一的,不可重复
  • 递增性:确保是整体逐渐增大的,这样有利于数据库创建索引
  • 安全性:ID的规律性不是特别的明显,防止根据ID号猜测其他的ID,确保安全性
  • 高性能:确保生成ID的速度足够快
  • 高可用:确保任何时候都能用

实现原理:

为了增加ID的安全性,可以不直接使用Redis自增的数值,而是拼接一些其他的信息,ID的组成如下图:

Redis全局ID生成器的实现

  • 符号位:1bit,永远为0,表示正数
  •  时间戳:31bit,以秒为单位,可以使用大约69年
  •  序列号:32bit,相同秒数的情况下,ID在序列号位置上增加,支持每秒产生2^32个不同的ID

代码实现:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
 
@Component
public class RedisIdWorker {
 
    /**
     * 开始时间戳 (2022-01-01 00:00:00)
     */
    private static final long BEGIN_TIMESTAMP = 1640995200L;
 
    /**
     * 序列号的位数
     */
    private static final int COUNT_BITS = 32;
 
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
 
    /**
     * 生成ID
     *
     * @param keyPrefix 业务系统的前缀
     * @return ID
     */
    public long nextId(String keyPrefix) {
        // 生成时间戳
        long timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) - BEGIN_TIMESTAMP;
        // 生成序列号
        String key = "icr:" + keyPrefix + ":" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        long count = stringRedisTemplate.opsForValue().increment(key);
        // 拼接并返回
        return timestamp << COUNT_BITS | count;
    }
 
    /**
     * 获取时间戳 (2022-01-01 00:00:00)
     * @param args
     */
    public static void main(String[] args) {
        LocalDateTime time = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        long second = time.toEpochSecond(ZoneOffset.UTC);
        System.out.println(second);
    }
}

生成序号:

Redis的自增是有上限的,最大值为2^64。虽然这个数是很大了,但是毕竟还有会有上限,时间足够长还是有可能超过这个数的。所以即使是同一个业务,也不能使用同一个key。因此可以在key中增加日期,比如:icr:业务名:2022:05:14。这样的话每天都会是新的key,每天的自增量不可能超过2^64,所以这样的key是比较合适的选择。

到此这篇关于Redis全局ID生成器的实现的文章就介绍到这了,更多相关Redis全局ID生成器内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Redis 相关文章推荐
详解Redis实现限流的三种方式
Apr 27 Redis
Redis5之后版本的高可用集群搭建的实现
Apr 27 Redis
Redis数据结构之链表与字典的使用
May 11 Redis
redis内存空间效率问题的深入探究
May 17 Redis
在redisCluster中模糊获取key方式
Jul 09 Redis
Redis性能监控的实现
Jul 09 Redis
Redisson实现Redis分布式锁的几种方式
Aug 07 Redis
聊聊redis-dump工具安装问题
Jan 18 Redis
Redis官方可视化工具RedisInsight安装使用教程
Apr 19 Redis
Redis keys命令的具体使用
Jun 05 #Redis
Redis入门基础常用操作命令整理
Jun 01 #Redis
Redis基本数据类型String常用操作命令
Jun 01 #Redis
Redis基本数据类型List常用操作命令
Jun 01 #Redis
Redis基本数据类型Set常用操作命令
Jun 01 #Redis
Redis基本数据类型哈希Hash常用操作命令
Jun 01 #Redis
Redis基本数据类型Zset有序集合常用操作
Jun 01 #Redis
You might like
PHP目录函数实现创建、读取目录教程实例
2011/01/13 PHP
PHP判断文件是否存在、是否可读、目录是否存在的代码
2012/10/03 PHP
PHP实现搜索相似图片
2015/09/22 PHP
示例详解Laravel的注册重构
2016/08/14 PHP
PHP数组的定义、初始化和数组元素的显示实现代码
2016/11/05 PHP
Laravel 6 将新增为指定队列任务设置中间件的功能
2019/08/06 PHP
PHP代码覆盖率统计详解
2020/07/22 PHP
ExtJS下grid的一些属性说明
2009/12/13 Javascript
JQuery入门——用one()方法绑定事件处理函数(仅触发一次)
2013/02/05 Javascript
jQuery浏览器CSS3特写兼容实例
2015/01/19 Javascript
浅谈javascript的调试
2015/01/28 Javascript
JS实现无限级网页折叠菜单(类似树形菜单)效果代码
2015/09/17 Javascript
非常棒的jQuery图片轮播效果
2016/04/17 Javascript
JS仿百度自动下拉框模糊匹配提示
2016/07/25 Javascript
详解JS异步加载的三种方式
2017/03/07 Javascript
vue-cli实现多页面多路由的示例代码
2018/01/30 Javascript
微信小程序之事件交互操作实例分析
2018/12/03 Javascript
layui form.render('select', 'test2') 更新渲染的方法
2019/09/27 Javascript
微信小程序淘宝首页双排图片布局排版代码(推荐)
2020/10/29 Javascript
详解uniapp的全局变量实现方式
2021/01/11 Javascript
centos下更新Python版本的步骤
2013/02/12 Python
Python中的random()方法的使用介绍
2015/05/15 Python
简单介绍Python中的几种数据类型
2016/01/02 Python
Python中将字典转换为列表的方法
2016/09/21 Python
Python实现批量检测HTTP服务的状态
2016/10/27 Python
Selenium控制浏览器常见操作示例
2018/08/13 Python
python装饰器常见使用方法分析
2019/06/26 Python
django实现支付宝支付实例讲解
2019/10/17 Python
使用python处理题库表格并转化为word形式的实现
2020/04/14 Python
python的reverse函数翻转结果为None的问题
2020/05/11 Python
《圆明园的毁灭》教学反思
2014/02/28 职场文书
企业文化标语口号
2014/06/09 职场文书
音乐教育专业自荐信
2014/09/18 职场文书
公司新员工欢迎词
2015/09/30 职场文书
积极心理学课程心得体会
2016/01/22 职场文书
《圆明园的毁灭》教学反思
2016/02/16 职场文书