多平台统一管理软件接口,如何实现多平台统一管理软件接口
2531
2024-02-04
对单机服务做接口限流的处理方案
设定某个接口一定时间只接受固定次数的请求,比如 /add 接口1秒最多接收100次请求,多的直接拒绝,直接上代码:
/** * 单机限流 */ @Slf4j public class FlowLimit { //接口限流上限值和限流时间缓存 private static Cache<String, AtomicLong> localCache = CacheBuilder.newBuilder().maximumSize(100) .expireAfterWrite(1000, TimeUnit.MILLISECONDS).build(); //每个接口的上限缓存 private static Map<String, Long> maxFlowLimitMap = new ConcurrentHashMap<>(); private static final FlowLimit instance = new FlowLimit(); //这块的目的是初始化每个接口的上限,下面的变量:apiFlowLimitConfigure //实际使用的时候应该是从db或者其他地方获取设置的每个接口的限流上限值, //这样可以动态的调整接口上限,比如直接修改db,不用发布,就可以调整接口限流值 static { new ScheduledThreadPoolExecutor(1, runnable -> { Thread thread = new Thread(runnable, "api-flowLimit-configure"); // thread.setDaemon(true); return thread; }).scheduleAtFixedRate(() -> { try { String apiFlowLimitConfigure = "{\"doAdd\":100}"; //表示/doAdd接口1秒接受100次请求 Map mapObj = JSONObject.parseObject(apiFlowLimitConfigure, Map.class); if(mapObj != null){ mapObj.forEach((key, value) -> { if(value != null){ instance.setMaxFlowLimit(key.toString(), new Long(value.toString())); }else{ log.warn(key + " - 设置接口限流发现限流值为空,设置默认值"); instance.setMaxFlowLimit(key.toString(), 100L); } }); } } catch (Exception e) { log.error("设置接口限流出现异常{}", e); } }, 0, 3, TimeUnit.SECONDS); } public static FlowLimit getInstance() { return instance; } private FlowLimit setMaxFlowLimit(String key, Long maxFlowLimit) { maxFlowLimitMap.put(key, maxFlowLimit); return this; } public Boolean isAvailable(String key) { return checkAvailable(key, 1L); } public Boolean isAvailable(String key, Long incrNum) { return checkAvailable(key, incrNum); } private Boolean checkAvailable(String key, Long incrNum){ Long maxFlowLimit = maxFlowLimitMap.get(key); if (null == maxFlowLimit || maxFlowLimit == 0) { return true; } if (incrAndGet(key, incrNum) <= maxFlowLimit.longValue()) { return true; } else { return false; } } private long incrAndGet(String key, final long n) { try { return localCache.get(key, new Callable<AtomicLong>() { @Override public AtomicLong call() throws Exception { return new AtomicLong(0); } }).addAndGet(n); } catch (Exception e) { log.error(e.getMessage(), e); } return 0; } public long get(String key) { return incrAndGet(key, 0); } }上面这个就是单机限流逻辑,代码不难,感觉没必要使用ConcurrentHashMap,不过感觉无所谓了
这段代码只需要加在需要限流的接口前面:@GetMapping("doAdd") public Boolean doAdd(){ FlowLimit instance = FlowLimit.getInstance(); //单例获取 //查看当前的/doAdd接口是否触发了限流 Boolean flowLimitFlag = instance.isAvailable("doAdd"); if(!flowLimitFlag){ log.warn("触发限流,拒绝请求"); return false; } //doAdd() return true; }调用实例如上
上面这个限流其实是有一定问题的:比如你限定10秒钟1000次,在第9.9秒的时候,突然进来1000个请求,然后第10.1秒的时候,攻击者,又进来1000次请求,这样,0.2秒之内,进来2000次请求。。。
所以这个时候就需要令牌桶或者其他算法了,其他算法后面再写没怎么仔细测试,有问题欢迎提出,共同学习
最近写了一个秒杀的功能模块,为了保证高并发情况下不会宕机,要从多方面去考虑,当前的限流操作只是其中的一个方面,具体操作如下。导入所需依赖<properties> <project. ...
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~