Redisson实现分布式计数器

实现思路:

项目中需要对异步操作的多个任务进行计数统计,且在这些任务完成时对任务执行情况进行保存,分布式环境下本地计数器显然不能适用了,于是考虑使用redis的Hash数据类型进行存储计数。Redisson的RMapCache对象提供的api便捷操作k,v结构数据同时兼具定期淘汰元素的机制,在其基础上做了一个计数器,记录一下。

1.初始化计数器,设置元素过期时间

 /**
   * 初始化计数器
   * @param batchId
   * @param totalCount
   */
  public void initCounter(Long batchId,Integer totalCount){
    RMapCache<String, Integer> mapCache = redissonClient.getMapCache(mapKey + batchId,
        IntegerCodec.INSTANCE);
    mapCache.put(totalKey + batchId, totalCount, 24, TimeUnit.HOURS);
    mapCache.put(countKey + batchId, 0, 24, TimeUnit.HOURS);
    mapCache.put(successKey + batchId, 0, 24, TimeUnit.HOURS);
    mapCache.put(failKey + batchId, 0, 24, TimeUnit.HOURS);
  }

2.执行计数统计

  /**
   * 执行成功计数
   * true:全部执行完成,false:未执行完成
   * @param batchId
   * @return
   */
  public Boolean executeCount(Long batchId,boolean successFlag){
    RMapCache<String, Integer> mapCache = redissonClient.getMapCache(mapKey+batchId, IntegerCodec.INSTANCE);
    if (successFlag){
      mapCache.addAndGet(successKey+batchId,1);
    }else {
      mapCache.addAndGet(failKey+batchId,1);
    }
    if (mapCache.addAndGet(countKey+batchId,1).equals(mapCache.get(totalKey+batchId))){
      log.info("任务执行完成,batchId is {}",batchId);
      return Boolean.TRUE;
    }else {
      return Boolean.FALSE;
    }
  }

3.查询执行情况

/**
   * 查询执行结果
   */
  public CountResult queryCounter(Long batchId) {
    RMapCache<String, Integer> mapCache = redissonClient.getMapCache(mapKey + batchId,
        IntegerCodec.INSTANCE);
    return CountResult.builder()
        .total(mapCache.get(totalKey + batchId))
        .count(mapCache.get(countKey + batchId))
        .success(mapCache.get(successKey + batchId))
        .fail(mapCache.get(failKey + batchId))
        .build();
  }

4.销毁RMapCache

  /**
   * 销毁RMapCache
   */
  public void destroy(Long batchId) {
    RMapCache<String, Integer> mapCache = redissonClient.getMapCache(mapKey + batchId,
        IntegerCodec.INSTANCE);
    mapCache.destroy();
  }

遇到的问题:

1.对获取到的RMapCache对象进行addAndGet操作时抛出异常,提示ERR Error running script (call to f_d00b594f5607f3847d85ee785709a65f57f98fff): @user_script:1: user_script:1: attempt to perform arithmetic on a nil value. channel,原因是在获取RMapCache对象时没有定义编码解码方式,增加参数IntegerCodec.INSTANCE后解决。

2.调用RMapCache对象的destroy()api后,redis上的数据并未清除,反复验证得出结论:调用destroy()方法后只会删除ConcurrentMap<String, EvictionTask> tasks中的任务,避免任务过多产生OOM,redis上的数据并不会清除,调用RMap接口的remove可以达到实时删除redis数据的目的,只调用destory()方法时,redis上的数据将在过期失效后清除。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值