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

 更新时间:2021年11月25日 09:02:01   作者:景川呀  
这篇文章主要为大家详细介绍了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次请求。。。
所以这个时候就需要令牌桶或者其他算法了,其他算法后面再写

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

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

相关文章

  • 如何实现Java中一个简单的LinkedList

    如何实现Java中一个简单的LinkedList

    LinkedList与ArrayList都是List接口的具体实现类。下面将介绍如何实现一个简单的LinkedList,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • Java List的remove()方法踩坑

    Java List的remove()方法踩坑

    Java的List在删除元素时,一般会用list.remove(o)/remove(i)方法。在使用时,容易触碰陷阱,本文就来介绍一下容易踩的坑,感兴趣的可以了解一下
    2021-10-10
  • 详解利用Spring加载Properties配置文件

    详解利用Spring加载Properties配置文件

    本篇文章主要介绍了详解利用Spring加载Properties配置文件,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • java实现点赞功能

    java实现点赞功能

    这篇文章主要为大家详细介绍了java实现点赞功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • java 解决异常 2 字节的 UTF-8 序列的字节2 无效的问题

    java 解决异常 2 字节的 UTF-8 序列的字节2 无效的问题

    这篇文章主要介绍了java 解决异常 2 字节的 UTF-8 序列的字节 2 无效的问题的相关资料,需要的朋友可以参考下
    2016-12-12
  • SpringCloud使用Nacos保存和读取变量的配置方法

    SpringCloud使用Nacos保存和读取变量的配置方法

    在使用SpringCloud开发微服务时,经常会遇到一些比较小的后台参数配置,这些配置不足以单独开一张表去存储,而且其他服务会读取该参数,这篇文章主要介绍了SpringCloud使用Nacos保存和读取变量,需要的朋友可以参考下
    2022-07-07
  • Java this super代码实例及使用方法总结

    Java this super代码实例及使用方法总结

    这篇文章主要介绍了Java this super代码实例及使用方法总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java中的三元运算(三目运算)以后用得到!

    Java中的三元运算(三目运算)以后用得到!

    Java提供了一个三元运算符,可以同时操作3个表达式,下面这篇文章主要给大家介绍了关于Java中三元运算(三目运算)的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • 一篇文章让你三分钟学会Java枚举

    一篇文章让你三分钟学会Java枚举

    这篇文章主要给大家介绍了如何通过三分钟学会Java枚举的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • SpringBoot RESTful风格入门讲解

    SpringBoot RESTful风格入门讲解

    RESTful是一种web软件风格,它不是标准也不是协议,它不一定要采用,只是一种风格,它倡导的是一个资源定位(url)及资源操作的风格,这篇文章主要介绍了SpringBoot使用RESTful接口
    2022-11-11

最新评论