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);
    }

}

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

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

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

猜你喜欢

转载自blog.csdn.net/qq_38254635/article/details/132054588
今日推荐