当前位置:   article > 正文

Redis设置hash,为不同的field设置不同的过期时间_redis hash field过期时间

redis hash field过期时间

Redis设置hash,为不同的field设置不同的过期时间

一、背景需求

最近做了一个小需求,由于系统对接,导致我们的系统在高峰的时候CPU飙升,所以需要在高峰的时候保护系统进程不受影响。
而且还需要我们知道当前对接的数据总量,并且可以实时释放,如果释放失败了,还需要定时释放,减少系统卡顿的同时,不能对第三方产生影响。

此处肯定有人想到令牌桶算法,或者redission。
SpringBoot基于guava集成令牌桶算法:https://blog.csdn.net/qq_38254635/article/details/126398730
SpringBoot集成Redisson:https://blog.csdn.net/qq_38254635/article/details/126398716
集成的虽好,但我们用的场景单一,集成还需要引入jar导致部署包变大,所以我们需要手动搞一个。

二、具体要求

1、可以知道当前存在的总量
2、可实时对每个变量进行调整
3、变量的关闭失败后,有自修复机制

三、代码实现

了解redisson的应该知道,可以参考其做一个简易版。

package com;

import com.alibaba.fastjson.JSONObject;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class Test {

    @Resource
    private StringRedisTemplate redisTemplate;

    private final static Integer SWITCH_COUNT = 3;
    public static final String BUSINESS = "business:";
    public static final String CHECK = "check";
    public static final String BUSINESS_CHECK = BUSINESS + CHECK;

    public Result doLink(String strJson) {
        if(!getCheck(strJson)) return Result.error("当前调用超上限,请稍后重试!");
        return Result.success();
    }

    private boolean getCheck(String code){
        Map<Object, Object> objectMap = redisTemplate.opsForHash().entries(BUSINESS_CHECK);
        //如果为空,则视为第一次使用,直接放行
        if(null == objectMap || objectMap.size() == 0) {
            this.setKey(code);
            return true;
        }
        //清洗数据,清理过期redis
        Integer count = 0;//当前有效总量
        for(Map.Entry<Object, Object> entry : objectMap.entrySet()){
            String user = entry.getKey().toString();
            if(StringUtils.isEmpty(redisTemplate.opsForValue().get(BUSINESS_CHECK + "_" + user))) {
                redisTemplate.opsForHash().delete(BUSINESS_CHECK, user);
                continue;
            }
            count++;
        }
        //校验是否超过上限
        if(count >= SWITCH_COUNT) return false;
        this.setKey(code);
        return true;
    }

    private void setKey(String code){
        redisTemplate.opsForHash().put(BUSINESS_CHECK, code, JSONObject.toJSONString(code));
        redisTemplate.opsForValue().set(BUSINESS_CHECK + "_" + code, code,1, TimeUnit.MINUTES);
    }

    //清理当前调用线程redis
    private void after(String code){
        redisTemplate.opsForHash().delete(BUSINESS_CHECK, code);
        redisTemplate.delete(code);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

仅提供一个思路:
大致思路,redis存一个hash,把hash中的field当做key再存一个有效期的key。
当线程结束时,手动回收hash中的field,及对应的key。
考虑回收会存在失败的情况,所以在使用的时候,需做一遍数据清洗。

此方式,仅适用于count较小时使用,允许调用次数较多时,数据清洗会很消耗性能。

整理不易,点个赞吧!☺☺☺

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/695080
推荐阅读
相关标签
  

闽ICP备14008679号