• Reids实战——优惠券秒杀(全局唯一ID生成策略)


    1 全局唯一ID生成策略

    每个店铺都可以发布优惠券:

    当用户抢购时,就会生成订单并保存到tb_voucher_order这张表中,而订单表如果使用数据库自增ID就存在一些问题: 

    1. id的规律性太明显

    2. 会受单表数据量的限制

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

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

     这就相当对应了我们Redis中String类型的方法,

    第一:高可用、高性能,这是毋庸置疑的,毕竟是基于Redis的

    第二:递增性

    第三:安全性

    对于安全性:我们可以不直接使用Redis自增的数值,而是拼接一些其它信息:

    符号位:1位

    时间戳:31位,可以使用69年

    序列号:32位,使用INCRBY生成,秒内的计数器,支持每秒2^32个不同的id

     实现方法如下:

    1.获取时间戳

    获取时间戳可以通过当前时间戳减去2022年1月1号的时间戳,获取时间戳的方法可以使用toEpochSecond方法转化为秒数。

    2.获取序列号

    获取序列号,因为为了不然redis中保存的key都为同一个,我们在key的后面加上了当前时间(今天),而且此做法还可以方便统计这一天生成的订单数

    然后就是通过Redis中的INCREBY方法生成序列号。

    3.拼接

    拼接就比较讲究了,虽然可以直接使用加号等字符串拼接方法进行进行拼接,但是最后拼接出来的只能是字符串

    要想最后获得一个Long类型的ID,我们可以这样做:

    首先分析一下这个id的组成:

    第一位为符号位,然后就是31的时间戳,然后就是序号。

    我们可以这么做,先把时间戳左移32位,这样后32位就只能是序列号。然后通过 |(或)来进行拼接序列号。(涉及位运算知识,计算机组成原理)

    这里注意:使用 | 或的原因是最开始都是序列号上都是00000,不管你序列号来的是0还是1,

    0 | (或)0还是0,0|(或)1也还是1,所以使用|(或)

    实现代码如下:

    1. package com.hmdp.utils;
    2. import org.springframework.data.redis.core.StringRedisTemplate;
    3. import org.springframework.stereotype.Component;
    4. import javax.annotation.Resource;
    5. import java.time.LocalDateTime;
    6. import java.time.ZoneOffset;
    7. import java.time.format.DateTimeFormatter;
    8. /**
    9. * @Author 华子
    10. * @Date 2022/11/28 19:54
    11. * @Version 1.0
    12. */
    13. @Component
    14. public class RedisIdWorker {
    15. @Resource
    16. private StringRedisTemplate stringRedisTemplate;
    17. //开始时间
    18. private static final Long BEGIN_TIMESTAMP = 1640995200L;
    19. private static final int COUNT_BITS = 32;
    20. public long nextId(String keyPrefix){
    21. // 1.获取时间戳
    22. LocalDateTime now = LocalDateTime.now();
    23. long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
    24. long timestamp = nowSecond - BEGIN_TIMESTAMP;
    25. // 2.获取序列号
    26. //2.1获取当前时间
    27. String date = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    28. //2.2生成序列号
    29. long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
    30. // 3.拼接并返回
    31. return timestamp << COUNT_BITS | count;
    32. }
    33. }

    这样就可以生成全局唯一ID啦~

  • 相关阅读:
    【云原生-k8s篇】管理容器的顶级 Kubernetes工具有哪些?
    <C++>初识多态,剖析virtual关键字
    Canal使用
    重磅!Vertica集成Apache Hudi指南
    TensorFlow入门(一、环境搭建)
    webrtc入门:12.Kurento下的RtpEndpoint和WebrtcEndpoint
    用python实现基本数据结构【03/4】
    Hyperspectral Imagery Classification Based on Contrastive Learning
    Linux内核调试工具——devmem
    CVE-2021-35042
  • 原文地址:https://blog.csdn.net/qq_59212867/article/details/128086510