对大量交易信息放入redis,且单一key数据量存在存储上限,单一key放置数据量,数据量大,使用数据是逻辑操作耗时较多,将数据存储方式进行优化,将数据分片存储,设置整体存储总量,设置每个分片存储size,分片过期时间,整体过期时间。优化后的逻辑已经经过生产验证,效果提升。
代码思路是:
1.在redis中设置一个set,用于存储分片key,在每次存储元素是set的key都会进行过期时间的延长。
2.分片中放入数据时,需要判断: 1) 当前是否存在分片,不存在,直接新建返回,
                             2)存在分片,且当前分片为达到设置的分片的最大数据量,(判断最新分片是否元素存储元素是否已经达到上限,未到达上限直接将元素,塞进去即可,并延长过期时间。若已到达分片size,在在创建新分片进行存储)
                             3)存在分片,且已经达到最大分片数据,那么清除最早的分片,将数据丢弃,并创建新的分片,将数据存储在最新的分片上,设置过期时间。

/**
      * 设置key比splitKey过期时间长,默认多1分钟
      */
  private static final int EXPIRE_ADD = 60;
    /**
      * 定义splitKey常量前缀。splitKey有两部分构成 [ 前缀+序号 ]
      */
     private static final String SPLIT_KEY_PAD = "MCT";
   /**
      * 分片添加数据redis种
      *
      * @param jedisCluster redis连接  jedisCluster 可以按照你的使用框架进行替换为对应的实例对象,但是下方中关于设置的相关操作也需要改为对应的语法。
      * @param key          一级key  信息中可区分的标识即可
      * @param hashFieldKey 存放hash时field的值 [使用信息中的唯一标识ID]
      * @param value        添加的数据对象 [商户交易]
      * @param limitSize    总存放大小,用以计算清理路由set [设置为1000*10]
      * @param shardingSize 数据每片大小 [推荐设置为1000]
      * @param sends        数据存放时间 [设置为1小时]
      * @return
      */
     public static AddRes add(JedisCluster jedisCluster,
                              String key, String hashFieldKey,
                              Object value, int limitSize, int shardingSize,
                              int sends) {
         //key值校验
         if (key == null || key.length() < 1) {
             logger.info("key参数值有误 {}", key);
             return null;
         }
         //hashFeildKey值校验
         if (hashFieldKey == null || hashFieldKey.length() < 1) {
             logger.info("hashFieldKey参数值有误 {}", hashFieldKey);
             return null;
         }
         //limitSize & splitSize & sends 值校验
         if (sends < 1 || shardingSize < 1 || limitSize < shardingSize) {
             logger.info("sends & splitSize & limitSize 有误 {},{},{}", sends, shardingSize, limitSize);
             return null;
         }        //二级splitKey计算
         SplitKeyDto splitKeyDto = generateSplitKey(jedisCluster, key, limitSize, shardingSize);
         String splitKey = splitKeyDto.getSplitKey();
         //返回值构建
         AddRes addRes = new AddRes(key, -1, splitKey, -1, -1, -1);
         //二级splitKey添加到路由zset
         if (splitKeyDto.isNew) {
             addRes.setSplitKeyAdd(jedisCluster.sadd(key, splitKey));
         }
         //重置大key过期
         addRes.setKeyExpire(jedisCluster.expire(key, sends + EXPIRE_ADD));
         //hash中添加交易
         addRes.setValueAdd(jedisCluster.hset(splitKey, hashFieldKey, JSON.toJSONString(value)));
         //设置splitKey过期
         addRes.setSplitKeyExpire(jedisCluster.expire(splitKey, sends));
         logger.info("key={},hashFieldKey={}添加结果:{}", key, hashFieldKey, addRes);
         return addRes;    }
 
  
  
  
  
  /**
      * 利用路由表计算出本次数据该放入的分片splitKey
      * 在生成分片splitKey时候会计算路由表大小,如果大小超过限制
      * 会做一次清理计算
      *
      * @param jedisCluster redis连接
      * @param key          一级key
      * @param limitSize    总存放大小,用以计算清理路由zset
      * @param shardingSize 数据每片大小
      * @return 本次数据该放入的分片key
      */
     private static SplitKeyDto generateSplitKey(JedisCluster jedisCluster, String key, int limitSize, int shardingSize) {
         SplitKeyDto res = new SplitKeyDto(true, String.format("%s_%s$1", SPLIT_KEY_PAD,key));
         Set<String> keys = jedisCluster.smembers(key);
         if (keys == null) {
             return res;
         }
         int keysSize = keys.size();
         if (keysSize < 1) {
             return res;
         }        long max = 1;
TreeSet<String> treeSet = new TreeSet<>((x, y) -> {
                 long longX = Long.valueOf(x.split("\\$")[1]);
                 long longY = Long.valueOf(y.split("\\$")[1]);
                 return (int) (longX - longY);
             });
         //路由表过大,做一次清理
         if (keysSize > limitSize / shardingSize) {
             //路由表排序[正序]
            
             treeSet.addAll(keys);
             max = Long.valueOf(treeSet.last().split("\\$")[1]);
             clearKeys(jedisCluster, key, treeSet, keysSize);
         } else {
              treeSet.addAll(keys);
             max = Long.valueOf(treeSet.last().split("\\$")[1]);
         }
         res.setNew(false);
         res.setSplitKey(String.format("%s_%s$%d", SPLIT_KEY_PAD,key, max));
         Long len = jedisCluster.hlen(res.getSplitKey());
         if (len >= shardingSize) {
             res.setNew(true);
             res.setSplitKey(String.format("%s_%s$%d", SPLIT_KEY_PAD,key, max + 1));
         }
         return res;
     }