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

1 全局唯一ID生成策略

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

Reids实战——优惠券秒杀(全局唯一ID生成策略)_第1张图片

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

1. id的规律性太明显

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

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

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

Reids实战——优惠券秒杀(全局唯一ID生成策略)_第2张图片

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

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

第二:递增性

第三:安全性

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

符号位:1位

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

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

Reids实战——优惠券秒杀(全局唯一ID生成策略)_第3张图片

 实现方法如下:

1.获取时间戳

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

2.获取序列号

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

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

3.拼接

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

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

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

Reids实战——优惠券秒杀(全局唯一ID生成策略)_第4张图片

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

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

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

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

实现代码如下:

package com.hmdp.utils;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * @Author 华子
 * @Date 2022/11/28 19:54
 * @Version 1.0
 */
@Component
public class RedisIdWorker {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    //开始时间
    private static final Long BEGIN_TIMESTAMP = 1640995200L;
    private static final int COUNT_BITS = 32;

    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("yyyyMMdd"));
        //2.2生成序列号
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
//        3.拼接并返回
        return timestamp << COUNT_BITS | count;
    }


}

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

你可能感兴趣的:(Redis,redis,数据库,缓存)