当前位置: 首页 > 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 训练…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...