Redis实战9-全局唯一ID

news2024/12/26 2:09:26

发布优惠券的时候,每个店铺都可以发布优惠券,当用户抢购的时候,优惠券表中的id如果使用数据库的自增长ID会存在以下问题:

1:id的规律太明显,容易被刷

2:当数据量很大的时候,会受到单表数据的限制

缺点场景分析:

id规律场景:如果我们的id具有太明显的规则,用户或者说商业对手很容易猜测出来我们的一些敏感信息,比如商城在一天时间内,卖出了多少单,这明显不合适。

单表限制:随着我们商城规模越来越大,mysql的单表的容量不宜超过500W,数据量过大之后,我们要进行拆库拆表,但拆分表了之后,他们从逻辑上讲他们是同一张表,所以他们的id是不能一样的, 于是乎我们需要保证id的唯一性。

全局ID生成器

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

唯一性、高可用、递增性、安全性、高性能

全局唯一ID生成策略:

UUID、Redis自增长、雪花算法、数据库自增

Redis自增ID策略:

1:每天一个key,方便统计订单量;

2:ID都在是时间戳+计数器

实战:基于Redis拼接其他信息来实现全局唯一ID

全局唯一ID使用long类型的,其中时间戳是基于某一个时间点开始的。比如我们从2022.11.26 23:00:00开始,可以使用69年。

思考1:获取当前时间的秒:

思考2:时间戳,怎么计算的?

使用当前时间的秒-初始时间的秒

思考3:序列号怎么设置?

使用Redis的setnx命令,最好加上当前年月日

思考4:怎么拼接?

因为我们需要返回的是long类型的,如果使用string拼接后,还要转换。还要知道,使用string拼接,当并发量很大的时候,也会有性能问题。那么我们应该怎么处理的?

注意:我们再来看看全局唯一ID的格式。如上图,我们可以看出,共64位,其中符号位是1个,时间戳是31位。序列号是32位,发现什么了吗?如果我们把时间戳向左移动32位(因为序列号是32位。向左移动位置,空出给序列号使用),是不是就是符号位+时间戳的了?

1:我们也知道计算机中左移动最快是x<<位数。

2:我们还需要知道,在计算机中 | 或计算:按位或运算“|”

根据上面,我们可以知道位运算序号后,就是序列号的值。序列号是多少,就是多少。

所以,我们可以知道拼接代码如下:timeStamp << 32 |no;

最终代码:

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;
 
/**
 * @author 凯哥Java
 * @description  基于Redis实现62位的全局唯一ID
 * @company
 *  */
@Component
public class RedisIdWorker {
 
    private static final long BEGIN_TIMESTAMP = 1669503600L;
 
 
    private final StringRedisTemplate stringRedisTemplate;
 
    /**
     * 序列号的位数
     */
    private static final int COUNT_BITS = 32;
 
    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }
 
    /**
     * 获取id
     * @param kyePrefix
     * @return
     */
    public long nextId(String kyePrefix){
        //1:生成时间戳 = 当前时间戳-开始时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timeStamp = nowSecond - BEGIN_TIMESTAMP;
 
        //2:生成序列号.使用sexNx.其中加上当前年月日
        //获取当前时间的你那月日
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        //开始32位序列号
        long  no = stringRedisTemplate.opsForValue().increment("icr:"+kyePrefix+":"+date);
        //3:拼接返回
        return timeStamp << COUNT_BITS |no;
 
    }
    /**
     * 获取到指定时间的毫秒
     * @param args
     */
    public static void main(String[] args) {
        LocalDateTime time = LocalDateTime.of(2022,11,26,23,00,00);
        long second = time.toEpochSecond(ZoneOffset.UTC);
        System.out.println(second);
 
    }
}
 
测试:使用多线程及countdownlatch
private ExecutorService executorService = Executors.newFixedThreadPool(500);
 
    @Resource
    private RedisIdWorker redisIdWorker;
 
    @Test
    public void RedisIdWorkerTest() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(300);
        Runnable task = ()->{
            for(int i = 0;i<100;i++){
                long id = redisIdWorker.nextId("myorder");
                System.out.println(id);
            }
            latch.countDown();
        };
 
        long begin = System.currentTimeMillis();
        for(int i = 0;i< 300;i++){
            executorService.submit(task);
        }
        latch.await();
        long endTime = System.currentTimeMillis();
        System.out.println("耗时:"+(endTime-begin));
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/183148.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三、分布式id,lua脚本,分布式锁,消息队列

文章目录优惠卷秒杀1.redis实现分布式ID2.优惠券秒杀下单3.超卖问题4.lua脚本5.分布式锁6.redis stream消息队列实现异步秒杀7.redis消息队列list实现消息队列PubSub实现消息队列stream实现消息队列stream的消息队列-消费者组学习黑马点评项目整理总结:https://www.bilibili.co…

5 个用于自动化的杀手级 Python 脚本

Python 是一种功能强大的语言&#xff0c;广泛用于自动执行各种任务。无论您是开发人员、系统管理员&#xff0c;还是只是想通过自动化日常任务来节省时间的人&#xff0c;Python 都能满足您的需求。 这里有 5 个 Python 脚本&#xff0c;可以帮助您自动执行各种任务 文章目录…

Spring Boot之Swagger

文章目录零 项目源码一 Swagger简介二 Spring Boot集成Swagger2.1 环境准备2.2 配置Swagger2.3 配置文档信息2.4 配置扫描接口2.5 配置开关Swagger2.6 配置API分组2.7 配置实体类2.8 常用注解零 项目源码 Swagger源码免费下载 一 Swagger简介 Swagger官网swagger是一款可以根…

深入开源和金融技术世界,《新程序员005》来了!

亲爱的 CSDN 以及《新程序员》的读者朋友们&#xff0c;《新程序员005&#xff1a;开源深度指南 & 新金融背后的科技力量》正式与大家见面&#xff01;现在&#xff0c;点击下方封面&#xff0c;即可订阅&#xff0c;立享电子书&#xff0c;纸质书将在春节后为大家寄出&…

9、循环语句

目录 一、while循环语句 二、do…while循环语句 三、for循环语句 1. for语句 2. foreach语句 一、while循环语句 while语句也称条件判断语句&#xff0c;它的循环方式为利用一个条件来控制是否要继续反复执行这个语句。 语法如下&#xff1a; 当条件表达式的返回值为真时…

【并发编程十三】c++原子操作(1)

【并发编程十三】c原子操作&#xff08;1&#xff09;一、改动序列1、改动序列2、预测执行二、原子操作及其类别1、原子操作2、非原子操作3、原子类型三、标准原子类型1、标准原子类型的两种实现方式2、原子操作的用途3、原子操作的宏四、操作std:atomic_flag1、简介2、使用说明…

jsp ssm宿舍报修换宿管理系统-宿管idea

目 录 1 1绪论 1 1.1 课题研究的背景 1 1.2 课题研究的意义 1 1.3 本文主要工作 1 2 关键技术介绍 3 2.1 JSP技术的简介 3 2.2 SSM框架 3 2.3 MYSQL数据库 4 2.4 MySQL环境配置 4 2.5 B/S架构 4 3 需求分析与可行性分析 5 3.1功能需求分析…

年后公司缺人,面了13个测试员,发现他们都有一个通病.....

公司缺人&#xff0c;面了不少测试&#xff0c;结果竟然没有一个合适的。 一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在10-20k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。 看简历很多都是3年工作经验&#xff0c;但面试中…

数据不幸丢失怎么办?恢复丢失数据的 7 大方法

有时&#xff0c;您的系统可能会无意中被数据丢失等不可预见的事件唤醒。数据丢失已成为我们数字经济中的普遍现象&#xff0c;其发生的方式多种多样&#xff0c;包括意外删除、病毒攻击、无法访问的分区、数据损坏&#xff0c;甚至更灾难性的情况&#xff0c;如数据盗窃。 不…

Spring进阶:3步引入MybatisPlus多数据源,详细配置及原理解析

前言 MybatisPlus(MP)作为mybatis的增强工具&#xff0c;提供了配置多数据源的扩展&#xff0c;通过简单的几步配置&#xff0c;即可使用注解轻松切换数据源。 以下是dynamic-datasource提供的功能列表&#xff1a; 使用方法 1&#xff0c;引入dynamic-datasource-spring-bo…

第六章 数组、排序和查找

一、数组&#xff08;P156&#xff09; 1. 数组介绍 数组可以存放多个同一类型的数据。数组也是一种数据类型&#xff0c;是引用类型。即&#xff1a;数(数据)组(一组)就是一组数据2. 数组的使用 2.1 使用方式1&#xff1a;动态初始化 数组的定义&#xff1a;数据类型 …

uniCloud 微信小程序登陆全流程demo

ps&#xff1a; 博主一向不喜欢废话&#xff0c;直接说几个点&#xff0c;你悟了就直接去试&#xff0c;可以不用看完&#xff0c;还是得自己去试印象才深刻&#xff0c;博主写博文就怕自己以后忘记做个笔记顺便能帮一个是一个 1、你要获取unionid 肯定得访问外网&#xff0c;u…

【C++初阶】六、STL---string(总)|为什么学习string类|标准库中的string类|string 类常用接口

目录 一、为什么学习string类 1.1 C语言中的字符串 1.2 字符串在OJ面试中 二、标准库中的string类 2.1 string 介绍 2.2 编码格式 三、string 类常用接口 3.1 Member functions&#xff08;成员函数&#xff09; 3.1.1 构造函数&#xff08;Construct&#xff09; 3.…

C++11 并发指南七(C++11 内存模型一:介绍)

C11 并发指南七(C11 内存模型一&#xff1a;介绍) 文章目录C11 并发指南七(C11 内存模型一&#xff1a;介绍)第六章主要介绍了 C11 中的原子类型及其相关的API&#xff0c;原子类型的大多数 API 都需要程序员提供一个 std::memory_order&#xff08;可译为内存序&#xff0c;访…

面试第一次被问到SDK测试,当时就懵了

01、是什么 客户端SDK是为第三方开发者提供的软件开发工具包&#xff0c;包括SDK接口、开发文档和Demo示例等。SDK和应用之间是什么关系呢&#xff1f;以云信即时消息服务为例&#xff0c;如下图所示&#xff0c;应用客户端通过调用云信SDK接口&#xff0c;进行消息等数据查询…

[前端笔记——CSS] 14.图像、媒体和表单元素

[前端笔记——CSS] 14.图像、媒体和表单元素1.CSS调整大小2.图片、媒体和表单元素2.1替换元素2.2 form元素2.3 举个实例1.CSS调整大小 一个空的<div>是没有尺寸的。如果在 HTML 文件中添加一个空<div> 并给予其边框&#xff0c;则会在页面上看到一条线。 <div…

【软件安装】ubuntu安装nvidia驱动,解决闪屏问题

Official Drivers | NVIDIA nvidia驱动下载官网&#xff0c;登陆速度是有点慢的&#xff0c;需要耐心等待 我的电脑是笔记本&#xff0c;ubuntu18.04.6&#xff0c;NVIDIA GeForce RTX 3050 Laptop GPU 天时地利人和的情况下&#xff0c;按照下面这篇博文就可以顺利安装nvidi…

【存储】etcd的存储是如何实现的(2)

在上一篇中&#xff0c;介绍了etcd底层存储的内容&#xff0c;包括wal、raft.MemoryStorage以及backend。在介绍backend时提到了backend只是etcd kv存储的一部分&#xff0c;负责持久化存储&#xff0c;backend加内存化treeIndex才构成etcd完整的支持mvcc的kv存储。所以这篇就来…

红队大量资产指纹探测工具和摄像头漏-洞渗-透和利用工具

红队大量资产指纹探测工具和摄像头漏-洞渗-透和利用工具。 Finger定位于一款红队在大量的资产中存活探测与重点攻-击系统指纹探测工具。在面临大量资产时候Finger可以快速从中查找出重点攻-击系统协助我们快速展开渗-透。 实际效果 URL批量扫描效果如下: 调用api进行资产收集效…

第九层(6):STL之queue

文章目录前情回顾queue概念queue容器需要注意的地方queue类内的构造函数queue类内的赋值操作queue类内的插入操作queue类内的删除操作queue类内的访问queue类内的大小操作下一座石碑&#x1f389;welcome&#x1f389; ✒️博主介绍&#xff1a;一名大一的智能制造专业学生&…