当前位置:

首页 > 编程开发 > 如何使用springboot整合RateLimiter限流

如何使用springboot整合RateLimiter限流

RateLimiter令牌桶原理图随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.令牌桶的另外一个好处是可以方便的改变速度.一旦需要提高速率,则按需提高放入桶中的令牌的速率.一般会定时(比如100毫秒)往桶中增加一定数量的令牌,有些变种算法则实时的计算应该增加的令牌的数量.令牌桶是一种常用的流量

本文目录

    RateLimiter令牌桶原理图

    如何使用springboot整合RateLimiter限流

    • 随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

    • 令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.

    令牌桶是一种常用的流量控制技术。令牌桶本身没有丢弃和优先级策略。

    原理

    1.令牌以一定的速率放入桶中。

    2.每个令牌允许源发送一定数量的比特。

    3.发送一个包,流量调节器就要从桶中删除与包大小相等的令牌数。

    4.如果没有足够的令牌发送包,这个包就会等待直到有足够的令牌(在整形器的情况下)或者包被丢弃,也有可能被标记更低的DSCP(在策略者的情况下)。

    5.桶有特定的容量,如果桶已经满了,新加入的令牌就会被丢弃。因此,在任何时候,源发送到网络上的最大突发数据量与桶的大小成比例。令牌桶允许突发,但是不能超过限制。

    方法摘要

    修饰符和类型方法和描述
      
    doubleacquire() 从RateLimiter获取一个许可,该方法会被阻塞直到获取到请求
    doubleacquire(int permits) 从RateLimiter获取指定许可数,该方法会被阻塞直到获取到请求
    static RateLimitercreate(double permitsPerSecond) 根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)
    static RateLimitercreate(double permitsPerSecond, long warmupPeriod, TimeUnit unit) 根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少个请求量),在这段预热时间内,RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率。(只要存在足够请求数来使其饱和)
    doublegetRate() 返回RateLimiter 配置中的稳定速率,该速率单位是每秒多少许可数
    voidsetRate(double permitsPerSecond) 更新RateLimite的稳定速率,参数permitsPerSecond 由构造RateLimiter的工厂方法提供。
    StringtoString() 返回对象的字符表现形式
    booleantryAcquire() 从RateLimiter 获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话
    booleantryAcquire(int permits) 从RateLimiter 获取许可数,如果该许可数可以在无延迟下的情况下立即获取得到的话
    booleantryAcquire(int permits, long timeout, TimeUnit unit) 从RateLimiter 获取指定许可数如果该许可数可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可数的话,那么立即返回false (无需等待)
    booleantryAcquire(long timeout, TimeUnit unit) 从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待)

    开始贴代码

    pom.xml

    
    
    
        com.google.guava
        guava
        28.2-jre
    

    自定义接口Limit

    package com.zjy.knife4j.inte;
    import java.lang.annotation.*;
    /**
     * 限流注解
     */
    @Inherited
    @Documented
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Limit {
        // 默认每秒放入桶中的token
        double limitNum() default 20;
        String name() default "";
    }

    aop切面

    package com.zjy.knife4j.aspect;
    import com.google.common.util.concurrent.RateLimiter;
    import com.zjy.knife4j.inte.Limit;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import java.lang.reflect.Method;
    import java.util.concurrent.ConcurrentHashMap;
    @Aspect
    @Component
    public class RateLimitAspect {
        /**日志对象*/
        private static final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
        private ConcurrentHashMap RATE_LIMITER  = new ConcurrentHashMap<>();
        private RateLimiter rateLimiter;
        @Pointcut("@annotation(com.zjy.knife4j.inte.Limit)")
        public void serviceLimit() {
        }
        @Around("serviceLimit()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            Object obj = null;
            //获取拦截的方法名
            Signature sig = point.getSignature();
            //获取拦截的方法名
            MethodSignature msig = (MethodSignature) sig;
            //返回被织入增加处理目标对象
            Object target = point.getTarget();
            //为了获取注解信息
            Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
            //获取注解信息
            Limit annotation = currentMethod.getAnnotation(Limit.class);
            double limitNum = annotation.limitNum(); //获取注解每秒加入桶中的token
            String functionName = msig.getName(); // 注解所在方法名区分不同的限流策略
            if(RATE_LIMITER.containsKey(functionName)){
                rateLimiter=RATE_LIMITER.get(functionName);
            }else {
                RATE_LIMITER.put(functionName, RateLimiter.create(limitNum));
                rateLimiter=RATE_LIMITER.get(functionName);
            }
            if(rateLimiter.tryAcquire()) {
                logger.info("执行成功!!!...做一些业务处理");
                return point.proceed();
            } else {
                logger.info("请求繁忙...做一些业务处理");
                return null;
            }
        }
    }

    RateLimiterController

    package com.zjy.knife4j.controller;
    import com.zjy.knife4j.inte.Limit;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    @RequestMapping("/ratelimiter")
    @RestController
    public class RateLimiterController {
        /**
         * 开启限流
         * @return
         */
        @GetMapping("/open")
        @Limit(limitNum = 1, name = "test1")
        public String openRateLimiter1() {
            System.out.println("【限流执行了....编写业务....】");
            return "限流执行了";
        }
        /**
         * 开启限流
         * @return
         */
        @GetMapping("/open2")
        @Limit(limitNum = 1, name = "test2")
        public String openRateLimiter2() {
            System.out.println("【限流执行了222】");
            return "限流执行了222";
        }
        /**
         * 未开启限流
         * @return
         */
        @GetMapping("/close")
        public String closeRateLimiter() {
            System.out.println("【不限流执行了】");
            return "不限流执行了";
        }
    }

    代码贴完了,开始测试

    启动服务,访问添加限流注解的接口

    如何使用springboot整合RateLimiter限流

    再访问没加注解的接口

    如何使用springboot整合RateLimiter限流

    控制台打印结果:

    如何使用springboot整合RateLimiter限流

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    springBoot项目常用目录有哪些
    springBoot项目常用目录有哪些

    springBoot项目常用目录springBoot项目的目录结构及名规范介绍基于SpringBoot开发时的目录结构及命名规范,通过介绍能够为你解决,在实际项目中如何规划目录结构?如何命名目录更规范?各个目录分别代表什么含义?等三个问题。目录说明servicex//项目名|-admin-ui//管理服务前端代码(一般将UI和SERVICE放到一个工程中,便于管理)|-servicex-auth//模块1|-servicex-common//模块2|-servicex-gateway//模块3|-serv

    解析SpringBoot和SpringMVC之间的异同
    解析SpringBoot和SpringMVC之间的异同

    解析SpringBoot和SpringMVC之间的异同SpringBoot和SpringMVC是Java领域中非常重要的开发框架。虽然它们都属于Spring框架的一部分,但是在使用和功能上有一些明显的区别。本文将对SpringBoot和SpringMVC进行比较,解析它们之间的异同。首先,让我们来了解一下SpringBoot。SpringBo

    探索SpringCloud和SpringBoot在微服务领域的不同应用方式
    探索SpringCloud和SpringBoot在微服务领域的不同应用方式

    近年来,随着云计算和分布式架构的兴起,微服务架构的应用越来越广泛。而SpringCloud和SpringBoot作为Java开发中的两个重要框架,对于微服务的实现起到了重要的作用。然而,很多人对于它们在微服务领域的不同应用方式还存在一定的疑惑。本文将从不同的角度探索SpringCloud和SpringBoot在微服务中的应用方式。首先,我们来了解一下Spri

    SpringBoot和SpringMVC有何区别?
    SpringBoot和SpringMVC有何区别?

    SpringBoot与SpringMVC的不同之处在哪里?SpringBoot和SpringMVC是两个非常流行的Java开发框架,用于构建Web应用程序。尽管它们经常分别被使用,但它们之间的不同之处也是很明显的。首先,SpringBoot可以被看作是一个Spring框架的扩展或者增强版。它旨在简化Spring应用程序的初始化和配置过程,以帮助开发人

    比较SpringBoot和SpringMVC的异同
    比较SpringBoot和SpringMVC的异同

    SpringBoot和SpringMVC都是Java开发中常用的框架,但它们之间有一些明显的差异。本文将探究这两个框架的特点和用途,并对它们的差异进行比较。首先,我们来了解一下SpringBoot。SpringBoot是由Pivotal团队开发的,它旨在简化基于Spring框架的应用程序的创建和部署。它提供了一种快速、轻量级的方式来构建独立的、可执行

    SpringBoot与SpringMVC的不同点是什么?
    SpringBoot与SpringMVC的不同点是什么?

    SpringBoot和SpringMVC是Java开发中常用的两个框架,它们都是由Spring框架所提供的,但在功能和使用方式上有着一些区别。本文将分别介绍SpringBoot和SpringMVC的特点和区别。一、SpringBoot的特点:简化配置:SpringBoot通过约定优于配置的原则,大大简化了项目的配置过程。它可以自动配置项目所需要的参数,开发人

    比较和选择指南:SpringCloud与SpringBoot的功能比较
    比较和选择指南:SpringCloud与SpringBoot的功能比较

    SpringCloud和SpringBoot是目前Java领域中最热门的开源框架,它们分别提供了一套完善的微服务架构和快速构建应用程序的解决方案。本文将对它们的功能进行比较,并给出选择指南,以帮助读者了解它们的优势和适用场景。SpringBoot是一个用于开发Java应用程序的框架,它提供了一个简化的开发流程,集成了大量常用的功能和组件,减少了开发者的工作量

    SpringCloud与SpringBoot:分析它们之间的相似与不同
    SpringCloud与SpringBoot:分析它们之间的相似与不同

    深入剖析SpringCloud和SpringBoot的异同引言:在构建企业级应用程序时,Spring框架已经成为开发者们的首选。它提供了一种简单而强大的方式来构建独立于平台的应用程序。Spring框架由两个核心模块组成:SpringBoot和SpringCloud。虽然它们都可以帮助开发者快速搭建应用程序,但它们的目标和用途存在一些差异。本文将深入剖析Spr

    从架构角度看SpringCloud与SpringBoot的差异
    从架构角度看SpringCloud与SpringBoot的差异

    从架构角度看SpringCloud与SpringBoot的差异引言:在当今的互联网时代,构建分布式系统已经成为了一种必要的需求。而SpringBoot和SpringCloud正是为了满足这个需求而诞生的。尽管它们都是由Spring框架所提供的解决方案,但从架构角度来看,它们存在着一些重要的差异。本文将从架构的角度出发,对SpringBoot和SpringCl

    Java API 开发中使用 SpringBoot 的利弊分析
    Java API 开发中使用 SpringBoot 的利弊分析

    JavaAPI开发中使用SpringBoot的利弊分析随着互联网的快速发展和技术的不断更新迭代,Java技术在开发中的广泛应用引起了人们的重视。而SpringBoot作为一种微服务架构的解决方案,已经逐渐成为Java开发中的热门选择。那么,在JavaAPI开发中使用SpringBoot,到底有哪些利弊呢?下面来分析一下。利:简化开发

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。