java单机接口限流处理方案详解

对单机服务做接口限流的处理方案

简单说就是设定某个接口一定时间只接受固定次数的请求,比如/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次请求。。。
所以这个时候就需要令牌桶或者其他算法了,其他算法后面再写

没怎么仔细测试,有问题欢迎提出,共同学习

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2021-11-24

Java 实现限流器处理Rest接口请求详解流程

Maven依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> </dependency> 代码 上代码,不废话. 首先是限流器代码. package com.huyi.csdn.tools.rate; import com.google.c

Java实现接口限流方案

本文实例为大家分享了Java实现接口限流方案的具体代码,供大家参考,具体内容如下 RateLimiter Google开源工具包Guava提供了限流工具类RateLimiter,基于令牌桶算法实现. 1.maven依赖: <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>27.1-jre</versio

Java使用Semaphore对单接口进行限流

目录 一.实战说明 1.1 效果说明 1.2 核心知识点 二. 环境搭建 三.限流演示 3.1 并发请求工具 3.2 效果示例图 一.实战说明 1.1 效果说明 本篇主要讲如何使用Semaphore对单接口进行限流,例如有如下场景 a. A系统的有a接口主要给B系统调用,现在希望对B系统进行限流,例如处理峰值在100,超过100的请求快速失败 b. 接口作为总闸入口,希望限制所有外来访问,例如某个房间只能同时100个玩家在线,只有前面的处理完后面的才能继续请求 c. 其他类型场景,也就是资源固定

SpringBoot服务上实现接口限流的方法

Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

Spring Cloud Alibaba使用Sentinel实现接口限流

最近管点闲事浪费了不少时间,感谢网友 libinwalan 的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一段落,后续与其他结合的内容等讲到的时候再一起拿出来说,不然内容会有点跳跃.接下来我们就来一起学习一下Spring Cloud Alibaba下的另外一个重要组件:Sentinel. Sentinel是什么 Sentinel的官方标题是:分布式系统的流量防卫兵.从名字上来看,很容易就能猜到它是用来

SpringMVC 限流的示例代码

在使用SpringBoot做接口访问如何做接口的限流,这里我们可以使用google的Guava包来实现,当然我们也可以自己实现限流,Guava中的限流是久经考验的我们没必需重新再去写一个,如果想了解限流原理的同学可以自己查阅一下相关的资料,本文不作过来说明噢. 使用说明 在项目中引入Guava相关包 http://mvnrepository.com/artifact/com.google.guava/guava/21.0 maven项目 <!-- https://mvnrepository.co

浅谈Koa服务限流方法实践

最近接了一个需求,很简单,就是起一个server,收到请求时调用某个提供好的接口,然后把结果返回.因为这个接口的性能问题,同时在请求的不能超过特定数目,要在服务中进行限流. 限流的要求是,限制同时执行的数目,超出这个数目后要在一个队列中进行缓存. koa 中间件不调用 next 最初的想法是在 koa 中间件中进行计数,超过6个时将next函数缓存下来.等正在进行中的任务结束时,调用next继续其他请求. 之后发现 koa 中间件中,不执行next函数请求并不会停下,而是不再调用之后的中间件,直

详解Spring Cloud Gateway 限流操作

开发高并发系统时有三把利器用来保护系统:缓存.降级和限流. API网关作为所有请求的入口,请求量大,我们可以通过对并发访问的请求进行限速来保护系统的可用性. 常用的限流算法比如有令牌桶算法,漏桶算法,计数器算法等. 在Zuul中我们可以自己去实现限流的功能 (Zuul中如何限流在我的书 <Spring Cloud微服务-全栈技术与案例解析>  中有详细讲解) ,Spring Cloud Gateway的出现本身就是用来替代Zuul的. 要想替代那肯定得有强大的功能,除了性能上的优势之外,Spr

浅谈java 面对对象(抽象 继承 接口 多态)

什么是继承? 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可. 多个类可以称为子类,单独这个类称为父类.超类或者基类. 子类可以直接访问父类中的非私有的属性和行为. 通过 extends 关键字让类与类之间产生继承关系. class SubDemo extends Demo{} //SubDemo是子类,Demo是父类 继承有什么好处? •提高代码的复用性. •让类与类之间产生了关系,是多态的前提. 继承的特点 1.Java只支

RateLimit-使用guava来做接口限流代码示例

本文主要研究的是RateLimit-使用guava来做接口限流的相关内容,具体如下. 一.问题描述 某天A君突然发现自己的接口请求量突然涨到之前的10倍,没多久该接口几乎不可使用,并引发连锁反应导致整个系统崩溃.如何应对这种情况呢?生活给了我们答案:比如老式电闸都安装了保险丝,一旦有人使用超大功率的设备,保险丝就会烧断以保护各个电器不被强电流给烧坏.同理我们的接口也需要安装上"保险丝",以防止非预期的请求对系统压力过大而引起的系统瘫痪,当流量过大时,可以采取拒绝或者引流等机制. 二.常

详解Java分布式IP限流和防止恶意IP攻击方案

前言 限流是分布式系统设计中经常提到的概念,在某些要求不严格的场景下,使用Guava RateLimiter就可以满足.但是Guava RateLimiter只能应用于单进程,多进程间协同控制便无能为力.本文介绍一种简单的处理方式,用于分布式环境下接口调用频次管控. 如何防止恶意IP攻击某些暴露的接口呢(比如某些场景下短信验证码服务)?本文介绍一种本地缓存和分布式缓存集成方式判断远程IP是否为恶意调用接口的IP. 分布式IP限流 思路是使用redis incr命令,完成一段时间内接口请求次数的统

详解Java 信号量Semaphore

Semaphore也是一个同步器,和前面两篇说的CountDownLatch和CyclicBarrier不同,这是递增的,初始化的时候可以指定一个值,但是不需要知道需要同步的线程个数,只需要在同步的地方调用acquire方法时指定需要同步的线程个数: 一.简单使用 同步两个子线程,只有其中两个子线程执行完毕,主线程才会执行: package com.example.demo.study; import java.util.concurrent.ExecutorService; import ja

java 中设计模式之单例

java 中设计模式之单例 设计模式思想 什么是设计模式:我作为初学者,今天第一次正式学习设计模式,我觉得对与理解什么是设计模式很重要,那么什么是设计模式呢? 设计模式:解决问题的一种行之有效的思想. 设计模式:用于解决特定环境下.重复出现的特定问题的解决方案 我的理解是前人在软件设计的时候碰到了一类问题,他们总结出了一套行之有效,并且经过验证的解决方案. 设计模式的优点: 1.设计模式都是一些相对优秀的解决方案,很多问题都是典型的.有代表性的问题,学习设计模式,我们就不用自己从头来解决这些问题