Redis学习笔记(五) | 青训营笔记

94 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天

前面学习了redis的一些基础操作和日常项目开发时使用缓存需要注意的几个问题,本节开始就是redis的一些实战代码。本节记录的是基于redis的全局唯一id生成器。

全局唯一ID

有些数据,例如账户等,与其他做外键连接需要一个全局唯一的标识,以防止数据冲突造成不可逆的破坏。一般来说,id有如下生成策略:

  • UUID
  • Redis自增
  • snowflake算法
  • 数据库自增

使用mysql开发时,全局唯一id一般使用雪花算法生成的id,这样生成的id可以保证在一个系统下唯一。然而在分布式系统下,这样生成的id可能也会出现重复的可能。因此,想要在分布式系统下实现全局唯一id,就需要另找他策。在进行redis的学习中,我学习到了基于redis的全局ID生成器,可在分布式系统下用来生成全局唯一ID的工具,同时具有唯一性,高可用,高性能,递增性,安全性的特点,可以较好地满足需求。

主要原理就是利用redis的步长自增,相当于分布式系统中用一个自增,redis的高性能可以满足这样生成id所需要的效率,同时配合时间戳就可生成一个分布式系统下的全局唯一id。

@Component
public class RedisIdWorker {

    //开始时间戳
    private static final long BEGIN_TIMESTAMP = 1640995200L;
    //序列号位数
    private static final long COUNT_BITS = 32;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     *
     * @param keyPrefix 业务前缀
     * @return 全局唯一id
     */
    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 day = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        //2.2自增长
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + day);

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