上一篇:https://blog.csdn.net/fengxianaa/article/details/124390301

服务集群部署的情况下,id的生成一直都是个问题,只靠数据库自增,这样会给数据库造成很大的压力,并且自增的规律比较明显,容易被他人得知,安全性不好

redis 可以实现高效的分布式ID生成

1. 原理

一般的主键都是Long类型,Long型数据是64位,我们把它分成3段

从左边开始

  • 第 1 段,只占 1 位,是符号位,一直为 0,保证不是负数
  • 第 2 段,占 31 位,最大2 ^ 31,用当前日期来表示,比如:20220101
    • 当前日期,其实就是一个 int 类型数字,最大 99999999,转换为二进制
      00000101 11110101 11100000 11111111
    • 远远小于 2 ^ 31,所以可以放心使用
  • 第 3 段,占 32 位,从0开始,顺序自增,最大2 ^ 32 ,四十多亿

这样每天最多可以生成 2 ^ 32 个ID,满足绝大多数业务

2. 代码

@Component
public class IDGenerator {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public long nextId(String businessKey){
        //1. 第 2 段,当前日期
        long today = Long.parseLong(LocalDate.now().toString().replace("-",""));

        //2. 第 3 段,递增序列号
        Long no = stringRedisTemplate.opsForValue().increment(businessKey + "_id_key");

        return today << 32 | no;
    }
}

解释一下:today << 32 | no; 这句代码

假设今天是2022-01-01

转换为二进制就是

00000000 00000000 00000000 00000000 00000001 00110100 10001000 11000101

然后左移 32 位,结果

00000001 00110100 10001000 11000101 00000000 00000000 00000000 00000000

假设从 redis 中获取的值是 100,转为二进制是

00000000 00000000 00000000 00000000 00000000 00000000 00000000 01100100

再进行 “|” 运算,结果

00000001 00110100 10001000 11000101 00000000 00000000 00000000 01100100

转成Long型:86844672516816996

3. 问题

使用这种方式最大的问题就是,需要确保 redis 不宕机,一旦宕机就可能导致业务系统的崩溃,

虽然 redis 也有持久化和集群的功能,但是 redis 主节点宕机后,其他节点并不能100%保证数据是最新的,所以还是有很大的风险

redis作为内存数据库,只能当作辅助功能,切记不能当成真正的数据库

关于主键的生成,最合适的是单独做成一个服务,后面会有专门的课题,目前主要是了解 原理

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐