【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的限流器RateLimiter功能服务

news2024/9/23 9:24:55

限流器的算法选项

随着互联网的快速发展,越来越多的应用程序需要处理大量的请求。如果没有限制,这些请求可能会导致应用程序崩溃或变得不可用。因此,限流器是一种非常重要的技术,可以帮助应用程序控制请求的数量和速率,以保持稳定和可靠的运行。

Java是一种非常流行的编程语言,具有广泛的应用场景。在Java中,实现限流器的方法有很多种。本文将介绍一些常见的实现方法和技术。

令牌桶算法

令牌桶算法是一种常见的限流算法,它基于一个令牌桶来控制请求的速率。在令牌桶算法中,令牌桶以固定的速率生成令牌,并将这些令牌存储在桶中。每当一个请求到达时,它必须从桶中获取一个令牌才能被处理。如果桶中没有足够的令牌,请求将被拒绝。

在Java中,可以使用Guava库中的RateLimiter类来实现令牌桶算法。RateLimiter类提供了一种简单而有效的方式来控制请求的速率。

接下来我们开发带着大家手把手去实现一个属于我们自己的限流器服务组件。

开发阶段

Maven的依赖配置

首先,我们需要开始配置Maven所具有的依赖关系,主要包含者基础的工具类配置信息包含了Hutools和apache-commons相关的
基础工具组件,以及针对于我们的限流器的服务库Guava。

   <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
  		 <dependency>
            <groupId>com.fengwenyi</groupId>
            <artifactId>JavaLib</artifactId>
            <version>2.1.6</version>
        </dependency>        
		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
        <!--joda-->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.0-jre</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.8</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
		 <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>        
    </dependencies>

核心服务类之间的关系

主要包含了各个服务类之间的关系,包含了继承关系以及服务功能的继承总览机制。
在这里插入图片描述

定义限流器基础接口

首先,我们先定义一下我们的基础接口-ExecuteRateLimiter。

@FunctionalInterface
public interface ExecuteRateLimiter<P,R>{

    /**
     * 执行操作
     * @param param
     * @return
     */
    R execute(P param);
}

这个各类主要代表限流器的执行操作方法。

定义限流器工厂方法

接下来,我们定义一下限流器工厂方法类ExecuteRateLimiterFactory。主要目的作为我们限流器的创建限流器的功能。

@FunctionalInterface
public interface ExecuteRateLimiterFactory<P,R> {
    R create(P param);
}

主要目的作为创建限流器ExecuteRateLimiter接口,接下来我们会进行覆盖和实现改接口进行构建不同厂商的限流器服务实现类。


Guava厂商的限流器所需要的参数类 — GuavaRateLimiterParam

在此,我们主要去实现我们 的限流器的参数实现类:GuavaRateLimiterParam。

@Builder
@Data
public class GuavaRateLimiterParam {

    private int permitsPerSecond;

    private int warmupPeriod;
 
    private TimeUnit timeUnit;
}

主要去属于封装了对应的Guava限流器的参数属性:

  • permitsPerSecond: 返回的RateLimiter的速率,意味着每秒有多少个许可变成有效。
  • warmupPeriod: 在这段时间内RateLimiter会增加它的速率,在抵达它的稳定速率或者最大速率之前
  • timeUnit:参数warmupPeriod 的时间单位

Guava厂商的限流器工厂类 — GuavaExecuteRateLimiterFactory

首先,我们需要进行实现属于我们Guava厂商的限流器的工厂类,主要目的是去实现对应的Guava的限流器的核心类:RateLimiter,并且作为我们Spring容器的一个组件进行注册到容器中去。

@Component
public class GuavaExecuteRateLimiterFactory implements ExecuteRateLimiterFactory<GuavaRateLimiterParam,RateLimiter> {

    /**
     * 创建RateLimiter对象
     * @param param
     * @return
     */
    @Override
    public RateLimiter create(GuavaRateLimiterParam param) {
        return RateLimiter.create(param.getPermitsPerSecond(),param.getWarmupPeriod(),param.getTimeUnit());
    }
}

实现面向切面模式的限流器实现功能

  • 限流器注解
  • 限流器切面

限流器注解

限流器的注解,主要面向于限流器的功能的参数包装,方便开发者可以再注解上进行定义不同的参数选项,基本等价于我们的GuavaRateLimiterParam的属性参数。可见:

@java.lang.annotation.Target({ElementType.METHOD,ElementType.FIELD})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Documented
@Component
@Autowired(required = false)
public @interface GuavaExecuteRateLimiter {

    /**
     * 返回的RateLimiter的速率,意味着每秒有多少个许可变成有效。
     */
    int permitsPerSecond() default 500;

    /**
     * 在这段时间内RateLimiter会增加它的速率,在抵达它的稳定速率或者最大速率之前
     */
    int warmupPeriod() default 5;

    /**
     * 参数warmupPeriod 的时间单位
     */
    TimeUnit timeUnit() default TimeUnit.SECONDS;

}

限流器切面

主要针对于限流器的切面类进行控制处理-GuavaExecuteRateLimterAspect类。

@Slf4j
@Aspect
@Component
public class GuavaExecuteRateLimterAspect {
    @Pointcut("@annotation(com.hyts.assemble.ratelimiter.guava.anno.GuavaExecuteRateLimiter)")
    public void methodPointCut() {}


    @Autowired
    GuavaExecuteRateLimiterFactory executeRateLimiterFactory;


    ConcurrentHashMap<String, RateLimiter> rateLimiterConcurrentHashMap = new ConcurrentHashMap<>();



    Joiner joiner = Joiner.on("-").skipNulls();



    @Around("methodPointCut()")
    public Object doMethod(ProceedingJoinPoint proceedingJoinPoint){
        MethodSignature methodSignature = (MethodSignature)proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        GuavaExecuteRateLimiter guavaExecuteRateLimiter = method.getAnnotation(GuavaExecuteRateLimiter.class);
        GuavaRateLimiterParam guavaRateLimiterParam = GuavaRateLimiterParam.builder().
                permitsPerSecond(guavaExecuteRateLimiter.permitsPerSecond()).
                timeUnit(guavaExecuteRateLimiter.timeUnit()).
                warmupPeriod(guavaExecuteRateLimiter.warmupPeriod()).build();
        String key = joiner.join(guavaExecuteRateLimiter.permitsPerSecond(),
                guavaExecuteRateLimiter.timeUnit().toString()
                ,guavaExecuteRateLimiter.warmupPeriod());
        RateLimiter rateLimiter = rateLimiterConcurrentHashMap.
                computeIfAbsent(key,param-> executeRateLimiterFactory.create(guavaRateLimiterParam));
        try {
            double rateValue = rateLimiter.acquire();
            log.info("执行限流方法操作处理:当前qps:{} delay rate limiter value:{}",guavaExecuteRateLimiter.permitsPerSecond(),rateValue);
            return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        } catch (Throwable e) {
            log.error("执行限流控制方法失败!",e);
            return null;
        }
    }
}

主要用于通过AOP进行实时构建GuavaExecuteRateLimiterFactory进行构建和创建对应的RateLimiter对象,并且缓存到对应的容器里面进行构建。
进行执行限流操纵控制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/464924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaEE初阶】多线程(四)阻塞队列 定时器 线程池

文章目录 多线程案例阻塞队列概念生产者消费者模型标准库中的阻塞队列自己实现一个阻塞队列 定时器概念标准库中的定时器实现定时器 线程池标准库中的线程池工厂模式 ThreadPoolExecutor();构造方法参数详解(重点)实现线程池 多线程案例 阻塞队列 概念 阻塞队列是一种特殊的…

【软考备战·希赛网每日一练】2023年4月26日

文章目录 一、今日成绩二、错题总结第一题 三、知识查缺 题目及解析来源&#xff1a;2023年04月26日软件设计师每日一练 一、今日成绩 二、错题总结 第一题 解析&#xff1a; 数据耦合&#xff1a;一组模块借助参数表传递简单数据。 公共耦合&#xff1a;多个模块都访问同一个…

C++题解 | 逆波兰表达式相关

✨个人主页&#xff1a; 夜 默 &#x1f389;所属专栏&#xff1a; C/C相关题解 &#x1f38a;每篇一句&#xff1a; 图片来源 A year from now you may wish you had started today. 明年今日&#xff0c;你会希望此时此刻的自己已经开始行动了。 文章目录 &#x1f307;前言…

改进YOLOv8 | 即插即用篇 | YOLOv8 引入 RepVGG 重参数化模块 |《RepVGG:让VGG风格的卷积神经网络再次伟大》

我们提出了一种简单但功能强大的卷积神经网络结构,该模型在推理时类似于VGG,只有33的卷积和ReLU堆叠而成,而训练时间模型具有多分支拓扑结构。训练时间和推理时间结构的这种解耦是通过结构重新参数化技术实现的,因此该模型被命名为RepVGG。在ImageNet上,RepVGG达到了超过8…

手把手教你搭建属于自己的服务器

最近总是想搭建自己的网站&#xff0c;奈何皮夹里空空如也&#xff0c;服务器也租不起&#xff0c;更别说域名了。于是我就寻思能否自己搭建个服务器&#xff0c;还不要钱呢&#xff1f; 还真行&#xff01;&#xff01;&#xff01; 经过几天的冲浪&#xff0c;我发现有两个免…

AlgoC++第七课:手写Matrix

目录 手写Matrix前言1. 明确需求2. 基本实现2.1 创建矩阵2.2 外部访问2.3 <<操作符重载 3. 矩阵运算3.1 矩阵标量运算3.2 通用矩阵乘法3.3 矩阵求逆 4. 完整示例代码总结 手写Matrix 前言 手写AI推出的全新面向AI算法的C课程 Algo C&#xff0c;链接。记录下个人学习笔记…

01 背包 (二维 )

首先是我对背包问题的理解&#xff1a; 有一个背包可以放下 n kg&#xff0c;有一些物品&#xff0c;价值和重量一一对应&#xff0c;问题是&#xff0c;需要怎样才能使背包中的价值最大&#xff1f; 不同的规则对应不同的背包问题 01背包&#xff1a;每一个物品只能被放入一次…

Docker consul的容器集群的部署|consul-template部署

Docker consul的容器集群的部署|consul-template部署 一、Consul 概述基于nginx和consul构建高可用及自动发现的Docker服务架构 二 consul实验步骤2.1 部署Consul集群 (server)2.2 Consul部署&#xff08;Client端&#xff09;2.3 consul-template部署(server)2.4 编译安装ngin…

【翻译一下官方文档】邂逅uniCloud云函数(基础篇)

我将用图文的形式&#xff0c;把市面上优质的课程加以自己的理解&#xff0c;详细的把&#xff1a;创建一个uniCloud的应用&#xff0c;其中的每一步记录出来&#xff0c;方便大家写项目中&#xff0c;做到哪一步不会了&#xff0c;可以轻松翻看文章进行查阅。&#xff08;此文…

量表题如何分析?

量表是一种测量工具&#xff0c;量表设计标准有很多&#xff0c;并且每种量表的设计都有各自的特性&#xff0c;不同量表的特性也决定了测量尺度&#xff0c;在数据分析中常用的量表为李克特量表。李克特量表1932年由美国社会心理学家李克特在当时原有总加量表的基础上进行改进…

Java8使用Stream流实现List列表简单使用

目录 1.forEach() 2.filter&#xff08;T -> boolean&#xff09; 3.findAny()和findFirst() 4.map(T -> R) 和flatMap(T -> stream) 5.distinct() 去重 6.limit(long n)和skip(long n) 7.anyMatch(T -> boolean) 8.allMatch(T -> boolean) 9.noneMat…

ASP.NET Core MVC 从入门到精通之数据库

随着技术的发展&#xff0c;ASP.NET Core MVC也推出了好长时间&#xff0c;经过不断的版本更新迭代&#xff0c;已经越来越完善&#xff0c;本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容&#xff0c;适用于初学者&#xff0c;在校毕业生&#xff0c…

ThingsBoard教程(三四):筛选规则节点 根据资产,设备,筛选,asset profile switch,device profile switch

前言 这是规则节点解析系列的第一篇,让我们先从Filter Nodes ,筛选节点类型开始。 筛选节点的作用主要是为了从筛选进入规则链的数据,根据一定的判断表达式来判断,数据向下游的那个分支流转。类似我们编程中的switch语句或if语句。 本篇主要讲解asset profile switch 与de…

每天一道算法练习题--Day13 第一章 --算法专题 --- ----------动态规划(重置版)

动态规划是一个从其他行业借鉴过来的词语。 它的大概意思先将一件事情分成若干阶段&#xff0c;然后通过阶段之间的转移达到目标。由于转移的方向通常是多个&#xff0c;因此这个时候就需要决策选择具体哪一个转移方向。 动态规划所要解决的事情通常是完成一个具体的目标&…

什么是渲染农场?我什么时候应该使用渲染农场?

网络上有关渲染农场的概念数不胜数&#xff0c;有一部分说法甚至让我们对渲染农场有了很大误解&#xff0c;究竟真正什么是渲染农场、渲染农场有多少种类型&#xff1f;我们怎么选择适合自己的渲染农场&#xff1f;这些都是各位小伙伴们近期比较关心的一些问题。 首先渲染农场是…

【C语言】基础语法7:文件操作

上一篇&#xff1a;字符串和字符处理 ❤️‍&#x1f525;前情提要❤️‍&#x1f525;   欢迎来到C语言基本语法教程   在本专栏结束后会将所有内容整理成思维导图&#xff08;结束换链接&#xff09;并免费提供给大家学习&#xff0c;希望大家纠错指正。本专栏将以基础出…

域内密码凭证获取

Volume Shadow Copy 活动目录数据库 ntds.dit&#xff1a;活动目录数据库&#xff0c;包括有关域用户、组和成员身份的 信息。它还包括域中所有用户的哈希值。 ntds.dit文件位置&#xff1a;%SystemRoot%\NTDS\NTDS.dit system文件位置&#xff1a;%SystemRoot%\System32\c…

好程序员:前端JavaScript全解析——Canvas绘制形状(下)

接着上一篇&#xff0c;好程序员继续讲解前端技术文章&#xff01; 绘制椭圆 ●canvas 也提供了绘制椭圆的 API ●语法 : 工具箱.ellipse( x, y, radiusX, radiusY, rotation, startAngle, endAngle, antiClockwise ) ○x : 椭圆中心点的 x 轴坐标 ○y : 椭圆中心点的 y 轴坐标…

Maven详解

一、什么是Maven Maven 是⼀个项⽬构建⼯具&#xff0c;创建的项⽬只要遵循 Maven 规范&#xff08;称为Maven项目&#xff09;&#xff0c;即可使用Maven 来进行&#xff1a;管理 jar 包、编译项目&#xff0c;打包项目等功能。 为什么学习 Servlet 之前要学 Maven&#xff1…

SAM(2023)-分割万物

文章目录 摘要算法数据引擎实验7.1 零样本单点生成mask7.2 零样本边缘检测7.3. 零样本目标Proposals7.4. 零样本实例分割7.5. 零样本文本生成Mask7.6. 消融实验 讨论限制&#xff1a;结论&#xff1a; 论文: 《Segment Anything》 github: https://github.com/facebookresear…