赞
踩
最近做了一个小需求,由于系统对接,导致我们的系统在高峰的时候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较小时使用,允许调用次数较多时,数据清洗会很消耗性能。
整理不易,点个赞吧!☺☺☺
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。