• 分布式Id


    本篇分享内容是关于生成分布式Id的其中之一方案,除了redis方案之外还有如:数据库,雪花算法,mogodb(object_id也是数据库)等方案,对于redis来说是我们常用并接触比较多的,因此主要谈谈结合redis生成分布式id方案。

    • 分布式Id设计流程图
    • 基于redis的hash自动increment累加生成有序Id
    • 定期删除无用hash列

    分布式Id设计流程图(有点粗略)

    基于redis的hash自动increment累加生成有序Id

    使用redis方案生成id,其中之一的方式主要使用increment(递增),不管是string、hash等都具有该方法,为了更方便管理我们id生成key这里建议使用hash的列的方式,以下内容都基于springboot分享;

    当然,第一步我们需要创建一个hash和hkey才行,至于在业务第一次被访问来创建这个hash还是通过服务自动创建这个看业务和流量,这里的hkey是有一定规则的(当然不用局限性),这里我按照日期格式来做key,可以有如下代码:

     1     /**
     2      * 生成每天的初始Id
     3      * @param hashName
     4      * @return
     5      */
     6     public String initPrimaryId(String hashName) {
     7         Assert.hasLength(hashName, "hashName不能为空");
     8 
     9         String hashCol = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    10         //自定义编号规则
    11         String hashColVal = hashCol + "00001";
    12         redisTemplate.opsForHash().putIfAbsent(hashName, hashCol, hashColVal);
    13         return hashCol;
    14     }

    上面很容易理解,hash中key是有每天日期格式组成,意思每天都需要生成一个新的日期key,通过putIfAbsent达到不重复添加的原则,至于hval可以根据自定义编号规则来生成一串数字字符(注:一定要数字);有了上面的基础,我们仅仅需要increment来累加,redis即帮我们完整hval+1的操作,当然可以自定义累加数,如下代码:

     1     /**
     2      * 获取分布式Id
     3      *
     4      * @param hashName
     5      * @return
     6      */
     7     public long getPrimaryId(String hashName) {
     8         try {
     9             String hashCol = initPrimaryId(hashName);
    10             return redisTemplate.opsForHash().increment(hashName, hashCol, 1);
    11         } catch (Exception ex) {
    12             ex.printStackTrace();
    13         }
    14         return 0;
    15     }

    定期删除无用hash列

    就上面我们通过hash来设置每天id只增初始值,hash的hkey布局用自动过期功能,因此我们需要代码中维护一套清除来hkey的机制,既然id是根据日期生成,我们可以就用往前推n天的方式达到清除老hkey目的:

     1     /**
     2      * 删除多少天之前的cols
     3      * @param hashName
     4      * @param lessDay
     5      * @return
     6      */
     7     public Long removePrimaryByLessDay(String hashName, int lessDay) {
     8         try {
     9             //当前日期
    10             String hashCol = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    11             long idl = Long.valueOf(hashCol) - lessDay;
    12 
    13             String[] removeCols = redisTemplate.opsForHash().entries(hashName).keySet().stream().
    14                     map(key -> key.toString()).
    15                     filter(key -> idl > Long.valueOf(key)).  //从+1开始,避免删除当天数据
    16                     toArray(String[]::new);
    17 
    18             if (ArrayUtils.isNotEmpty(removeCols)) {
    19                 return redisTemplate.opsForHash().delete(hashName, removeCols);
    20             }
    21         } catch (Exception ex) {
    22             ex.printStackTrace();
    23         }
    24         return 0L;
    25     }

    按照日期来生成分布式id,达到id不重复的目的,这也就是分布式id(不重复),看起来简单其实如果在高流量冲击下,需要考虑的东西要很多,比如:什么时候生成初始Id、在多个服务器保证服务器时间尽可能一样情况下,该保留多少日期hkey等;

    就上面代码对初始Id就做的不是很好,在业务获取Id时候,会去检测并创建id,这样与redis交互就多了一次,通常可以用服务来一次性生成当前日期往后推n天的hkey,这样就避免了在业务获取id时候,还要去putIfAbsent一次验证,减少了请求次数。实在不行可以使用lua脚本放在一次请求去做put和increment,你可能会用到:

    1             RedisScript script = new DefaultRedisScript("");
    2             redisTemplate.execute(script, Arrays.asList(""));
  • 相关阅读:
    MySQL优化点
    MySQL中lock tables和unlock tables浅析
    在深度计算框架MindSpore中如何对不持续的计算进行处理——对数据集进行一定epoch数量的训练后,进行其他工作处理,再返回来接着进行一定epoch数量的训练——单步计算
    Attributes should be specified via @SpringBootApplication
    base-package的路径不对,导致@Autowire提示trainingRepository错误。
    测试框架之-断言与预期结果 AssertJ
    无效的目标版本8 和 Unsupported major.minor version 52
    UML类图中箭头和线条的含义和用法
    苏宁乔新亮:世界上最好的研发管理十条经验
    4-8 路由实战
  • 原文地址:https://www.cnblogs.com/wangrudong003/p/11502305.html
Copyright © 2020-2023  润新知