当前位置: 首页 > news >正文

项目中如何进行限流(限流的算法、实现方法详解)

❤ 作者主页:李奕赫揍小邰的博客
❀ 个人介绍:大家好,我是李奕赫!( ̄▽ ̄)~*
🍊 记得点赞、收藏、评论⭐️⭐️⭐️
📣 认真学习!!!🎉🎉

文章目录

  • 限流的算法
    • 漏桶算法
    • 令牌桶算法
  • 限流粒度
  • 限流实现构思
    • 1.本地限流(单机限流)
    • 2.分布式限流(多机限流)
  • Redisson 限流实现
    • 1.先引入依赖
    • 2.创建 RedissonConfig 配置类,用于初始化 RedissonClient 对象单例;
    • 3.编写 RedisLimiterManager
    • 4.在项目引用

  最近在写一个项目,需要控制用户使用系统的次数,以避免超支,比如给不同等级的用户分配不同的调用次数,防止用户过度使用系统造成破产。现在要做一个解决方案,就是限流,比如说限制单个用户在每秒只能使用一次,那这里我们怎么去思考这个限流的阈值是多少?多少合适呢?
  参考正常用户的使用,比如限制单个用户在每秒只能使用 1 次。
 

限流的算法

  限流的算法有很多,常用的有两个漏桶算法和令牌桶算法,接下来会讲一下这两个算法的用法。

漏桶算法

  它的原理很简单,可以认为就是注水漏水的过程。往漏桶中以任意速率流入水,以固定的速率流出水。当水超过桶的容量时,会被溢出,也就是被丢弃。因为桶容量是不变的,保证了整体的速率。
在这里插入图片描述
1.流入的水滴,可以看作是访问系统的请求,这个流入速率是不确定的。
2.桶的容量一般表示系统所能处理的请求数。
3.如果桶的容量满了,就达到限流的阀值,就会丢弃水滴(拒绝请求)
4.流出的水滴,是恒定过滤的,对应服务按照固定的速率处理请求。
伪代码如下:

 /*** 每秒处理数(出水率)*/private long rate;/***  当前剩余水量*/private long currentWater;/*** 最后刷新时间*/private long refreshTime;/*** 桶容量*/private long capacity;/*** 漏桶算法* @return*/boolean leakybucketLimitTryAcquire() {long currentTime = System.currentTimeMillis();  //获取系统当前时间long outWater = (currentTime - refreshTime) / 1000 * rate; //流出的水量 =(当前时间-上次刷新时间)* 出水率long currentWater = Math.max(0, currentWater - outWater); // 当前水量 = 之前的桶内水量-流出的水量refreshTime = currentTime; // 刷新时间// 当前剩余水量还是小于桶的容量,则请求放行if (currentWater < capacity) {currentWater++;return true;}// 当前剩余水量大于等于桶的容量,限流return false;}

没有办法迅速处理一批请求,面对突发流量的时候,漏桶算法还是循规蹈矩地处理请求,按照固定速率处理请求,这不是我们想要的结果。
 

令牌桶算法

  面对突发流量的时候,我们可以使用令牌桶算法限流。

令牌桶算法原理:
1.有一个令牌管理员,根据限流大小,定速往令牌桶里放令牌。
2.如果令牌数量满了,超过令牌桶容量的限制,那就丢弃。
3.系统在接受到一个用户请求时,都会先去令牌桶要一个令牌。如果拿到令牌,那么就处理这个请求的业务逻辑;
4.如果拿不到令牌,就直接拒绝这个请求。
在这里插入图片描述
伪代码如下:

   /*** 每秒处理数(放入令牌数量)*/private long putTokenRate;/*** 最后刷新时间*/private long refreshTime;/*** 令牌桶容量*/private long capacity;/*** 当前桶内令牌数*/private long currentToken = 0L;/*** 漏桶算法* @return*/boolean tokenBucketTryAcquire() {long currentTime = System.currentTimeMillis();  //获取系统当前时间long generateToken = (currentTime - refreshTime) / 1000 * putTokenRate; //生成的令牌 =(当前时间-上次刷新时间)* 放入令牌的速率currentToken = Math.min(capacity, generateToken + currentToken); // 当前令牌数量 = 之前的桶内令牌数量+放入的令牌数量refreshTime = currentTime; // 刷新时间//桶里面还有令牌,请求正常处理if (currentToken > 0) {currentToken--; //令牌数量-1return true;}return false;}

如果令牌发放的策略正确,这个系统即不会被拖垮,也能提高机器的利用率。Guava的RateLimiter限流组件,就是基于令牌桶算法实现的
 

限流粒度

1.针对某个方法限流,即单位时间内最多允许同时 XX 个操作使用这个方法
2.针对某个用户限流,比如单个用户单位时间内最多执行 XX 次操作
3.针对某个用户 x 方法限流,比如单个用户单位时间内最多执行 XX 次这个方法
 

限流实现构思

1.本地限流(单机限流)

  每个服务器单独限流,一般适用于单体项目,就是你的项目只有一个服务器 。
  在 Java 中,有很多第三方库可以用来实现单机限流:Guava RateLimiter:这是谷歌 Guava 库提供的限流工具,可以对单位时间内的请求数量进行限制。


import com.google.common.util.concurrent.RateLimiter;public static void main(String[] args) {// 每秒限流5个请求RateLimiter limiter = RateLimiter.create(5.0);while (true) {if (limiter.tryAcquire()) {// 处理请求} else {// 超过流量限制,需要做何处理}}
}

 

2.分布式限流(多机限流)

  如果你的项目有多个服务器,比如微服务,那么建议使用分布式限流。
1.把用户的使用频率等数据放到一个集中的存储进行统计;
比如 Redis,这样无论用户的请求落到了哪台服务器,都以集中存储中的数据为准。
(Redisson – 是一个操作 Redis 的工具库)
2.在网关集中进行限流和统计(比如 Sentinel、Spring Cloud Gateway)

//redission
import org.redisson.Redisson;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;public static void main(String[] args) {// 创建RedissonClientRedissonClient redisson = Redisson.create();// 获取限流器RSemaphore semaphore = redisson.getSemaphore("mySemaphore");// 尝试获取许可证boolean result = semaphore.tryAcquire();if (result) {// 处理请求} else {// 超过流量限制,需要做何处理}
}

 

Redisson 限流实现

  Redisson 内置了一个限流工具类,可以帮助你利用 Redis 来存储、来统计。

1.先引入依赖

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.21.3</version>
</dependency>

2.创建 RedissonConfig 配置类,用于初始化 RedissonClient 对象单例;

application.yml文件
在这里插入图片描述
RedissonConfig 配置类

@Configuration
@ConfigurationProperties(prefix = "spring.redis")
@Data
public class RedissonConfig {private Integer database;private String host;private Integer port;private String password;@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setDatabase(database).setAddress("redis://" + host + ":" + port);RedissonClient redisson = Redisson.create(config);return redisson;}
}

3.编写 RedisLimiterManager

  Manager是专门提供 RedisLimiter 限流基础服务的(提供了通用的能力,可以放到任何一个项目里)。

@Service
public class RedisLimiterManager {@Resourceprivate RedissonClient redissonClient;/*** 限流操作** @param key 区分不同的限流器,比如不同的用户 id 应该分别统计*/public void doRateLimit(String key) {RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);// 限流器的统计规则(每秒2个请求;连续的请求,最多只能有2个请求被允许通过)// RateType.OVERALL表示速率限制作用于整个令牌桶,即限制所有请求的速率rateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);// 每当一个操作来了后,请求一个令牌boolean canOp = rateLimiter.tryAcquire(1);// 如果没有令牌,还想执行操作,就抛出异常if (!canOp) {throw new BusinessException(ErrorCode.TOO_MANY_REQUEST);}}
}

之后进行一下测试即可。

4.在项目引用

伪代码,只需要引入RedisLimiterManager 类,直接在需要限流的地方加上即可,例如给用户加上限流,就是每个用户每秒只允许请求两次

@Resource
private RedisLimiterManager redisLimiterManager;User loginUser = userService.getLoginUser(request);
// 限流判断,每个用户一个限流器
redisLimiterManager.doRateLimit("user_" + loginUser.getId());

相关文章:

项目中如何进行限流(限流的算法、实现方法详解)

❤ 作者主页&#xff1a;李奕赫揍小邰的博客 ❀ 个人介绍&#xff1a;大家好&#xff0c;我是李奕赫&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 记得点赞、收藏、评论⭐️⭐️⭐️ &#x1f4e3; 认真学习!!!&#x1f389;&#x1f389; 文章目录 限流的算法漏…...

https在win7的环境下如何配置

https在win7的环境下如何配置&#xff1f;在Windows7环境下配置https&#xff0c;需要完成以下步骤&#xff1a; 1&#xff09;安装Web服务器软件 可以选择安装常用的Web服务器软件&#xff0c;如Apache、Nginx或IIS&#xff0c;这些服务器软件都支持https。 2&#xff09;获…...

Day69:WEB攻防-Java安全JWT攻防Swagger自动化算法签名密匙Druid泄漏

目录 Java安全-Druid监控-未授权访问&信息泄漏 黑盒发现 白盒发现 攻击点 Java安全-Swagger接口-导入&联动批量测试 黑盒发现 白盒发现 自动化发包测试 自动化漏洞测试 Java安全-JWT令牌-空算法&未签名&密匙提取 识别 JWT 方式一&#xff1a;人工识…...

Python Windows系统 虚拟环境使用

目录 1、安装 2、激活 3、停止 1、安装 1&#xff09;为项目新建一个目录&#xff08;比如&#xff1a;目录命名为learning_log&#xff09; 2&#xff09;在终端中切换到这个目录 3&#xff09;执行命令&#xff1a;python -m venv ll_env&#xff0c;即可创建一个名为ll…...

栈和队列的学习

存储方式分两类&#xff1a;顺序存储和链式存储 栈&#xff1a;只允许从一端进行数据插入和删除的线性表&#xff1a;先进后出 FILO 队列&#xff1a;只允许从一端进行数据插入&#xff0c;另一端进行数据删除的线性表&#xff1a;先进先出 FIFO 栈 创建空栈&#xff0c;创建…...

【机器学习】基于机器学习的分类算法对比实验

摘要 基于机器学习的分类算法对比实验 本论文旨在对常见的分类算法进行综合比较和评估&#xff0c;并探索它们在机器学习分类领域的应用。实验结果显示&#xff0c;随机森林模型在CIFAR-10数据集上的精确度为0.4654&#xff0c;CatBoost模型为0.4916&#xff0c;XGBoost模型为…...

民航电子数据库:mysql与cae建表语法差异

目录 一、场景二、语法差异 一、场景 1、使用CAEMigrator-1.0.exe将mysql数据库迁移至cae数据库时&#xff0c;迁移速度非常慢&#xff0c;而且容易卡死&#xff08;可能是部署cae数据库的服务器资源不足导致&#xff09; 2、所以将mysql数据库导出为sql脚本&#xff0c;通过…...

(学习日记)2024.03.15:UCOSIII第十七节:任务的挂起和恢复

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…...

聚类分析 | Matlab实现基于NNMF+DBO+K-Medoids的数据聚类可视化

聚类分析 | Matlab实现基于NNMFDBOK-Medoids的数据聚类可视化 目录 聚类分析 | Matlab实现基于NNMFDBOK-Medoids的数据聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 NNMFDBOK-Medoids聚类&#xff0c;蜣螂优化算法DBO优化K-Medoids 非负矩阵分解&#xff08…...

Unity类银河恶魔城学习记录11-3 p105 Inventory UI源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_itemSlot.cs using System.Collections; using System.Collections.Gen…...

Vue3 + Vite + ts引入本地图片

Vue3 Vite ts引入本地图片 单张图片导入 单个图片导入&#xff0c;不过多阐述&#xff0c;通过 import 导入需要使用的图片。 import imgName from /assets/img/imgName.png 多张图片导入 new URL() import.meta.url import.meta.url 是一个 ESM 的原生功能&#xff0…...

图斑或者道路如何单独显示名称在图斑上或者道路上

0序&#xff1a; 遇到过多个测绘、工程、林业相关业务的客户&#xff0c;在加载一些图斑数据&#xff0c;线路数据时&#xff0c;希望能够单独的把图斑的名称&#xff0c;显示到图斑上&#xff0c;或者路网上面。 之前多数推荐的办法&#xff1a; 1.shp可以直接在图新地球中…...

docker 修改默认存储位置

一般系统下系统盘可能磁盘空间有限&#xff0c;需要将docker的存储目录改到其他位置 docker info 查看docker的版本 低版本docker在配置json中增加"graph":"/var/lib/docker" 高版本docker在配置json中增加"data-root":"/var/lib/docker&q…...

Springboot+vue的医疗挂号管理系统+数据库+报告+免费远程调试

效果介绍: Springbootvue的医疗挂号管理系统&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 本文设计了一个基于Springbootvue的前后端分离的医疗挂号管理系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;con…...

【Effective C++】39 明智而审慎地使用private继承

在之前论证过c如何将public 继承视为 is-a 关系。在哪个例子里&#xff0c;class Student 以 public 形式继承class Person&#xff0c; 于是编译器在必要时刻将Students暗自转化为Person.如果此时我们以 private 继承替换 public继承。 class Person {...}; class Student: p…...

2024年卫生巾行业市场分析报告(京东天猫淘宝线上卫生巾品类电商数据查询)

最近&#xff0c;相关部门辟谣了一则“十大致癌卫生巾黑名单”的消息。这个榜单是部分博主AI撰写&#xff0c;为博眼球、蹭热度的结果。此次事件势必会对卫生巾行业产生一定影响&#xff0c;加剧行业竞争。 根据鲸参谋电商数据平台显示&#xff0c;2024年1月至2月线上电商平台…...

MySQL之表的记录操作

前言 存数据不是目的&#xff0c;目的是能够将存起来的数据取出来或者查出来&#xff0c;并且能够对数据进行增删改查操作&#xff0c;本文将详细介绍表中记录的增删改查操作。对记录的操作属于DML数据库操作语言&#xff0c;可以通过SQL实现对数据的操作&#xff0c;包括实现…...

一种动态联动的实现方法

安防领域中的联动规则 有安防领域相关的开发经历的人知道&#xff0c;IPCamera可以配置使能“侦测”功能&#xff0c;并且指定仅针对图像传感器的某个区载进行侦测。除了基本的“移动侦测"外&#xff0c;侦测的功能点还有细化的类别&#xff0c;如人员侦测、车辆侦测、烟…...

kotlin中使用ViewBinding绑定控件

kotlin中使用ViewBinding绑定控件 什么是ViewBinding&#xff1f; View Binding是Android Studio 3.6推出的新特性&#xff0c;主要用于减少findViewById的冗余代码&#xff0c;但内部实现还是通过使用findViewById。通过ViewBinding&#xff0c;可以更轻松地编写可与视图交互…...

知识积累(五):Transformer 家族的学习笔记

文章目录 1. RNN1.1 缺点 2. Transformer2.1 组成2.2 Encoder2.2.1 Input Embedding&#xff08;嵌入层&#xff09;2.2.2 位置编码2.2.3 多头注意力2.2.4 Add & Norm 2.3 Decoder2.3.1 概览2.3.2 Masked multi-head attention 2.4 Transformer 模型的训练和推理2.4.1 训练…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

Linux 下 DMA 内存映射浅析

序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存&#xff0c;但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程&#xff0c;可以参考这篇文章&#xff0c;我觉得写的非常…...