当前位置: 首页>后端>正文

Redis-全局唯一ID

零、本文纲要

  • 一、全局唯一ID
  • 二、Redis生成全局唯一ID
    1、snowflake算法全局唯一ID策略
    2、Redis自增全局唯一ID策略
  • 三、代码实现

tips:Ctrl + F快速定位所需内容阅读吧。

一、全局唯一ID

1、全局唯一ID特点

  • ① 全局唯一性
  • ② 高性能
  • ③ 单调递增
  • ④ 信息安全
  • ⑤ 高可用

2、全局唯一ID生成策略

  • ① UUID
  • ② Redis自增
  • ③ snowflake算法
  • ④ 数据库自增
  • ⑤ Zookeeper的znode版本生成ID

二、Redis生成全局唯一ID

1、snowflake算法全局唯一ID策略

此处我们参考snowflake算法的ID策略,其具体策略如下:

① 1位,固定位;
② 41位,用来记录时间戳(毫秒),接近69年;
③ 10位,用来记录工作机器id;
④ 12位,序列号,用来记录同毫秒内产生的不同id;

Redis-全局唯一ID,第1张
snowflake算法的ID策略.png

2、Redis自增全局唯一ID策略

自定义我们自己的Redis自增的ID策略,具体如下:

① 1位,固定位;
② 31位,用来记录时间戳(秒),接近69年;
③ 32位,序列号,用来记录同一秒内产生的不同id;

Redis-全局唯一ID,第2张
Redis自增的ID策略.png

三、代码实现

1、获取开始时间戳

LocalDateTime#of(int year, int month, int dayOfMonth, int hour, int minute, int second)方法,传入自己需要的起始年月日时分秒;

    public static void main(String[] args) {
        LocalDateTime time = LocalDateTime.of(2022,1,1,0,0,0);
        long l = time.toEpochSecond(ZoneOffset.UTC);
        System.out.println(l);
    }

如:2022年1月1日 00点00分00秒,为1640995200L

2、编写ID生成工具类

@Component注解,将工具类注册到Spring容器当中,方便使用;
BEGIN_TIMESTAMP自定义起始的时间戳;
COUNT_BITS位移量,后续拼接全局唯一ID时使用;

@Component
public class RedisIdWorker {

    // 开始时间戳
    private static final long BEGIN_TIMESTAMP = 1640995200L;
    // 位移量
    private static final long COUNT_BITS = 32L;

    private StringRedisTemplate stringRedisTemplate;

    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    public long nextId(String keyPrefix){...}

}

timestamp获取当前设置起始时间戳的偏移量;
拼接key,例如:incr:order:20220325;
位运算拼接全局ID,timestamp << COUNT_BITS | count;

    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 currentDate = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        //2.2 自增长
        // 拼接的key,例如:incr:order:20220325
        long count = stringRedisTemplate.opsForValue().increment(
                RedisConstants.INCR_ID
                + keyPrefix
                + RedisConstants.SEPARATE
                + currentDate);

        //3. 拼接并返回
        return timestamp << COUNT_BITS | count;
    }

3、测试生成全局唯一ID

注入RedisIdWorker对象,用于测试;

    @Resource
    private RedisIdWorker redisIdWorker;

编写测试方法:

① 使用线程池模拟并发调用,此处简单处理;

    private ExecutorService es = Executors.newFixedThreadPool(500);

② 使用CountDownLatch控制线程执行;

        CountDownLatch latch = new CountDownLatch(300); //设置300阈值

        Runnable task = () -> {
            ...
            latch.countDown();//每次循环结束,latch -1
        };

        ... //开始时间
        ... //执行任务
        latch.await();//等待直到 latch 变为 0
        ... //结束时间

完整的测试方法如下:

    @Test
    public 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);
            }
            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("time = " + (end - begin));
    }

四、结尾

以上即为Redis全局唯一ID的基础内容,感谢阅读。


https://www.xamrdz.com/backend/3be1995443.html

相关文章: