限流原理与实践:固定窗口、滑动窗口、漏桶与令牌桶解析

方案一、固定窗口限流算法

这里我们通过一个 demo 来介绍固定窗口限流算法。

  1. 创建一个 FixWindowRateLimiterService 类。
@Service
public class FixWindowRateLimiterService {@Resourceprivate StringRedisTemplate stringRedisTemplate;private static final DefaultRedisScript<Long> LIMIT_SCRIPT;/*** 是否运行请求通过** @param key     Redis key* @param max     允许请求通过的最大数* @param timeout 一个窗口的时间* @return true:通过 false:限流*/public boolean isAllowed(String key, Long max, Long timeout) {Long signal = stringRedisTemplate.execute(LIMIT_SCRIPT,Collections.singletonList(key),String.valueOf(max),String.valueOf(timeout));if (Objects.isNull(signal)) {return false;}//返回 0,则说明就是限流return signal != 0;}static {LIMIT_SCRIPT = new DefaultRedisScript<>();LIMIT_SCRIPT.setLocation(new ClassPathResource("RateLimiterLua.lua"));LIMIT_SCRIPT.setResultType(Long.class);}
}
  1. 写一个 lua 脚本(保证线程安全),lua 脚本要放在 resources 的根目录下
local key = KEYS[1]
local max = tonumber(ARGV[1])
local timeout = tonumber(ARGV[2])
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > max thenreturn 0
elseredis.call("INCRBY", key, 1)redis.call("EXPIRE", key, timeout)return current + 1
end
  1. 测试
    在这里插入图片描述
    注意,固定窗口算法存在边界问题,下图介绍了窗口问题。

方案二、滑动窗口限流算法

滑动窗口限流算法相对固定窗口限流算法更复杂一些,但更为精确。下面是一个基于 Redis 的 zset 结构 实现的简单滑动窗口限流的例子。

@RestController
public class RateLimitController {private static final String KEY = "rate:limit";private static final int MAX_VISIT = 1;@Resourceprivate RedisTemplate redisTemplate;@ResponseBody@GetMapping("/visit")public String visit() {//1970-01-01T00:00:00Z 到现在的秒数long now = Instant.now().getEpochSecond();//移除现在这个时刻往前推 60s 的访问统计数redisTemplate.opsForZSet().removeRangeByScore(KEY, 0, now - 60);//获取当前的访问统计数Long currentVisits = redisTemplate.opsForZSet().zCard(KEY);if (currentVisits >= MAX_VISIT) {return "请稍后再试~";} else {redisTemplate.opsForZSet().add(KEY, String.valueOf(now), now);return "访问成功~";}}
}

方案三、漏桶限流算法

这个算法的基本思想就像有一个漏洞的桶一样。漏桶以一定的速度出水,当水流入过大的时候溢出。通过这个思想来进行流量的控制。

在程序实现中,漏桶通常以一个队列的形式存在,在有新的请求先进入队列中。队列以一定的速率处理请求,当队列满了以后,新进入的请求就会被拒绝。

下面是一个漏桶算法的 demo。在这个例子中,我们创建了一个容量为 10 的桶,每秒可以漏水两个(也就是系统每秒可以处理两个请求)。每当有新请求到来时,我们先计算桶里还剩多少水,如果没满则把请求加进去,满了就拒绝请求。

public class LeakyBucketDemo {/*** 桶的容量*/private final long capacity = 10L;/*** 水流出的速度*/private final long rate = 2L;/*** 当前水量(实际上就是请求书)*/private long water = 0L;/*** 上次漏水时间*/private long lastTime = System.currentTimeMillis();public boolean tryConsume() {long now = System.currentTimeMillis();//计算当前水量water = Math.max(0, water - (now - lastTime) * rate);lastTime = now;//判断剩余空间是否足够if ((water + 1) < capacity) {water++;return true;} else {return false;}}public static void main(String[] args) {LeakyBucketDemo leakyBucketDemo = new LeakyBucketDemo();for (int i = 0; i < 11; i++) {System.out.println(leakyBucketDemo.tryConsume() ? "请求通过" : "请求被限流");}}
} 

方案四、令牌桶限流算法

这个算法的思想是在一个常量固定速率下,把令牌放到令牌桶中。当请求来临的时候,令牌桶中有令牌则请求成功,没有令牌则请求失败。每请求成功一次,就会桶令牌丢到一个令牌。

下面是一个使用 Google 开源的 Guava 库来做限流算法的 demo。

public class TokenBucketDemo {private final RateLimiter rateLimiter = RateLimiter.create(10);public void doRequest() {if (rateLimiter.tryAcquire()) {System.out.println("正常处理请求");} else {System.out.println("限流");}}public static void main(String[] args) throws InterruptedException {TokenBucketDemo tokenBucketDemo = new TokenBucketDemo();for (int i = 0; i < 20; i++) {Thread.sleep(1000);tokenBucketDemo.doRequest();}}
}

总结

四种限流算法各有优缺点,需要根据自己的业务场景选择使用。推荐项目比较复杂的时候使用成熟的框架,比如sentinel。

  1. 固定窗口限流算法:适用于对精度要求不高,对性能要求比较高的场景。
  2. 滑动窗口限流算法:适用于对限流精度比较高的场景。
  3. 漏桶限流算法:适用于访问速率绝对稳定的场景。
  4. 令牌桶限流算法:适用于访问速率相对比较稳定的场景,但也可以应对一定的突发流量的场景。(对于使用 Guava 实现的方案,如果自己的项目是分布式的,那么此方案不适用 --Guava 是单机的)

最后

我是 xiucai,一位后端开发工程师。

如果你对我感兴趣,请移步我的个人博客,进一步了解。

  • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊
  • 本文首发于个人博客,未经许可禁止转载💌

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

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

相关文章

[Toolschain cpp ros cmakelist python vscode] 记录写每次项目重复的设置和配置 不断更新

写在前面 用以前的设置&#xff0c;快速配置项目&#xff0c;以防长久不用忘记&#xff0c;部分资料在资源文件里还没有整理 outline cmakelist 复用vscode 找到头文件vscode debug现有代码直接关联远端gitros杂记repo 杂记glog杂记 cmakelist 复用 包含了根据系统路径找库…

Jenkins Docker Cloud在Linux应用开发CI中的实践

Jenkins Docker Cloud在Linux应用开发CI中的实践 背景 通过代码提交自动触发CI自动构建、编译、打包是任何软件开发组织必不可少的基建&#xff0c;可以最大程度保证产物的一致性&#xff0c;方便跨组跨部门协作&#xff0c;代码MR等。 Docker在流水线中越来越重要&#xff…

服务器解析漏洞是什么?攻击检测及修复

服务器解析漏洞&#xff08;Server-side Include Vulnerability&#xff0c;SSI漏洞&#xff09;是一种安全漏洞&#xff0c;通常出现在支持服务器端包含&#xff08;SSI&#xff09;功能的Web服务器上。SSI是一种在Web页面中嵌入动态内容的技术&#xff0c;允许开发人员将外部…

3d游戏公司选择云电脑进行云办公有哪些优势

随着游戏行业的不断发展&#xff0c;很多的游戏制作公司也遇到了很多的难题&#xff0c;比如硬件更换成本高、团队协同难以及效率低下等问题&#xff0c;那么如何解决游戏行业面临的这些行业痛点&#xff0c;以及游戏制作公司选择云电脑进行云办公有哪些优势&#xff1f;一起来…

云原生之深入解析Kubernetes集群发生网络异常时如何排查

一、Pod 网络异常 网络不可达&#xff0c;主要现象为 ping 不通&#xff0c;其可能原因为&#xff1a; 源端和目的端防火墙&#xff08;iptables, selinux&#xff09;限制&#xff1b; 网络路由配置不正确&#xff1b; 源端和目的端的系统负载过高&#xff0c;网络连接数满…

Zookeeper-快速开始

Zookeeper介绍 简介&#xff1a;ZooKeeper 是一个开源的分布式协调框架&#xff0c;是Apache Hadoop 的一个子项目&#xff0c;主要用来解决分布式集群中应用系统的一致性问题。 设计目标&#xff1a;将那些复杂且容易出错的分布式一致性服务封装起来&#xff0c;构成一个高效…

OpenCV消除高亮illuminationChange函数的使用

学更好的别人&#xff0c; 做更好的自己。 ——《微卡智享》 本文长度为1129字&#xff0c;预计阅读4分钟 导语 上一篇《OpenCV极坐标变换函数warpPolar的使用》中介绍了极坐标变换的使用&#xff0c;文中提到过因为手机拍的照片&#xff0c;部分地方反光厉害。OpenCV本身也有一…

我的创作纪念日——成为创作者第1024天

机缘 一、前言 早上收到CSDN的推送信息&#xff0c;今天是我成为创作者的第1024天&#xff0c;回想起自己已经好久没有写博客了&#xff0c;突然间很有感触&#xff0c;想水一篇文章&#xff0c;跟小伙伴们分享一下我的经历。 二、自我介绍 我出生在广东潮汕地区的一个小城…

10000字讲解TCP协议(确认应答,超时重传,三次握手,四次挥手等等众多机制)以及UDP协议(UDP报文,校验和)

文章目录 UDP协议&#xff1f;什么是校验和&#xff1f;基于UDP的应用层协议(了解) TCP协议确认应答(可靠性机制)超时重传(可靠性机制)连接管理(可靠性机制)三次握手(重点)四次挥手(重点) 三次握手和四次挥手时客户端和服务器的状态滑动窗口(效率机制)流量控制(效率机制)窗口探…

智能优化算法应用:基于学生心理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于学生心理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于学生心理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.学生心理学算法4.实验参数设定5.算法…

HTML5+CSS3小实例:花瓣样式Loading加载动画效果

目录 一、运行效果 图片效果 二、项目概述 三、开发环境 四、实现步骤及代码 1.创建空文件夹 2.完成页面内容 3.完成css样式 五、项目总结 六、源码获取 一、运行效果 图片效果 二、项目概述 这个项目是一个加载动画效果&#xff0c;用于展示一个花瓣样式的…

长短期记忆(LSTM)神经网络-多输入分类

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分程序&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&am…

RabbitMQ 高级

1.发送者的可靠性 首先&#xff0c;我们一起分析一下消息丢失的可能性有哪些。消息从发送者发送消息&#xff0c;到消费者处理消息&#xff0c;需要经过的流程是这样的&#xff1a; 消息从生产者到消费者的每一步都可能导致消息丢失&#xff1a; 发送消息时丢失&#xff1a; 生…

持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布

目录 一、实验 1.环境 2.GitLab 更新deployment文件 3.GitLab更新共享库前端项目CI与CD流水线 4.K8S查看前端项目版本 5.Jenkins 构建前端项目 6.Jenkins 再次构建前端项目 二、问题 1. Jenkins 构建CI 流水线报错 2. Jenkins 构建CI 流水线弹出脚本报错 3. Jenkins…

AI性能再提升12.5%,ZStack Cube 超融合一体机基于第五代英特尔®至强®可扩展处理器解决方案发布

12月15日&#xff0c;以“Al无处不在&#xff0c;创芯无所不及”为主题的2023英特尔新品发布会暨AI技术创新派对上&#xff0c;云轴科技ZStack与英特尔联合发布基于第五代英特尔 至强 可扩展处理器的 ZStack Cube 超融合一体机解决方案白皮书&#xff08;简称解决方案&#xff…

【HarmonyOS开发】ArkUI中的自定义弹窗

弹窗是一种模态窗口&#xff0c;通常用来展示用户当前需要的或用户必须关注的信息或操作。在弹出框消失之前&#xff0c;用户无法操作其他界面内容。ArkUI 为我们提供了丰富的弹窗功能&#xff0c;弹窗按照功能可以分为以下两类&#xff1a; 确认类&#xff1a;例如警告弹窗 Al…

C# 调用腾讯混元大模型

写在前面 今天用C#调用了一下腾讯混元大模型&#xff0c;调用代码贴一下&#xff0c;具体的效果等深入使用后再来评价。 GitHub - TencentCloud/tencentcloud-sdk-dotnet: Tencent Cloud API 3.0 SDK for .NET 腾讯混元大模型简介_腾讯混元大模型购买指南_腾讯混元大模型操作…

代码随想录27期|Python|Day18|二叉树|路径总和iii|找树左下角的值|从中序与后序遍历序列构造二叉树

第一次刷的时候题解都不是精简版 513. 找树左下角的值 - 力扣&#xff08;LeetCode&#xff09; 注意这道题不是寻找最左侧的左节点&#xff0c;而是寻找最底层位于左端的节点&#xff08;可能是左节点&#xff0c;有可能是右节点&#xff09;。 层序遍历 层序遍历比较简单&…

Oracle的学习心得和知识总结(三十)| OLTP 应用程序的合成工作负载生成器Lauca论文翻译及学习

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《Oracle Database SQL Language Reference》 2、参考书籍&#xff1a;《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Gui…

springMVC-数据格式化

1、基本介绍 在一个springmvc项目中&#xff0c;当表单提交数据时&#xff0c;如何对表单提交的数据进行格式的转换呢&#xff1f; 只要是数据进行网络传输都是以字符串的形式&#xff0c;进入内存后才有数据类型。 springmvc在上下文环境内置了一些转换器&#xff0c…