对前端限流操作(Redis版本)4种算法

news2025/1/22 23:01:33

固定时间窗口算法

  • 固定时间窗口算法也可以叫做简单计数算法。网上有很多都将计数算法单独抽离出来。但是笔者认为计数算法是一种思想,而固定时间窗口算法是他的一种实现
  • 包括下面滑动时间窗口算法也是计数算法的一种实现。因为计数如果不和时间进行绑定的话那么失去了限流的本质了。就变成了拒绝了

在这里插入图片描述

优点

  • 在固定的时间内出现流量溢出可以立即做出限流。每个时间窗口不会相互影响
  • 在时间单元内保障系统的稳定。保障的时间单元内系统的吞吐量上限

缺点

  • 正如图示一样,他的最大问题就是临界状态。在临界状态最坏情况会受到两倍流量请求
  • 除了临界的情况,还有一种是在一个单元时间窗内前期如果很快的消耗完请求阈值。那么剩下的时间将会无法请求。这样就会因为一瞬间的流量导致一段时间内系统不可用。这在互联网高可用的系统中是不能接受的。

实现

	@Autowired
    private StringRedisTemplate redisTemplate;

    // 固定时间窗口算法
    @GetMapping("/start")
    public Map<String, Object> start(@RequestParam Map<String, Object> paramMap) {
        //根据前端传递的qps上线
        int times = 100;
        if (paramMap.containsKey("times")) {
            times = Integer.parseInt(paramMap.get("times").toString());
        }
        String redisKey = "redisQps";
        RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(redisKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
        int no = redisAtomicInteger.getAndIncrement();
        //设置时间固定时间窗口长度 1S
        if (no == 0) {
            redisAtomicInteger.expire(1, TimeUnit.SECONDS);
        }
        //判断是否超限  time=2 表示qps=3
        log.info("no值->{}",no);
        if (no > times) {
            throw new RuntimeException("qps refuse request");
        }
        log.info("times值->{}",times);
        //返回成功告知
        Map<String, Object> map = new HashMap<>();
        map.put("success", "success");
        return map;
    }

测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

滑动时间窗口算法

滑动时间窗口算法是一种限流算法,其原理是记录一段时间内的请求数量,并根据时间窗口的滑动来判断是否接受新的请求。该算法通过维护一个滑动窗口来记录时间窗口内的请求数量,并根据窗口的大小和限流阈值来决定是否接受新的请求。

滑动时间窗口算法的实现方式相对复杂一些,但相对于固定时间窗口算法更加灵活和精确。在滑动时间窗口算法中,时间窗口是不断滑动的,每个窗口的大小和起点可以根据实际需求进行配置。同时,该算法也支持动态调整限流阈值和流量控制粒度,能够更好地应对流量波动和突发请求的情况。

滑动时间窗口算法的核心思想是通过维护一个时间窗口内的请求计数器,并根据时间窗口的滑动来判断是否接受新的请求。具体来说,当一个新的请求到达时,算法会根据当前时间点判断该请求属于哪个时间窗口,并更新对应窗口的计数器。如果计数器已经达到了限流阈值,则拒绝该请求;否则,接受该请求。随着时间的推移,时间窗口会不断滑动,并更新计数器的值。

滑动时间窗口算法相对于固定时间窗口算法更加灵活和精确,能够更好地应对流量波动和突发请求的情况。同时,该算法也支持动态调整限流阈值和流量控制粒度,能够更好地满足实际需求。在实际应用中,需要根据具体情况选择适合的限流算法来控制流量。

优点

滑动时间窗口算法的优点主要包括以下几点:

  1. 灵活性和可配置性强:滑动时间窗口算法的时间窗口大小和起点可以根据实际需求进行配置,同时限流阈值也可以动态调整,这使得算法能够更好地应对流量波动和突发请求的情况。
  2. 精度高:滑动时间窗口算法相对于固定时间窗口算法更加精确,因为它考虑了时间窗口内的请求数量和时间点,能够更好地反映请求的实际情况。
  3. 支持多维度限流:滑动时间窗口算法可以支持多维度的限流,例如根据IP地址、用户ID、接口等不同维度进行限流,这使得算法能够更加精细地控制流量。

缺点

然而,滑动时间窗口算法也存在一些缺点:

  1. 实现复杂度高:滑动时间窗口算法的实现相对复杂,需要维护一个滑动窗口来记录时间窗口内的请求数量,并不断更新窗口的值,这需要耗费更多的计算和存储资源。
  2. 内存占用大:由于滑动时间窗口算法需要记录每个时间窗口内的请求数量和时间点,因此需要占用更多的内存资源。
  3. 无法平滑地实现请求流量的控制:滑动时间窗口算法只能通过控制时间段来控制请求总量,无法平滑地实现请求流量的控制,这可能会影响到用户体验和系统的稳定性。

实现

  • 滑动时间窗口是将时间更加细化,上面我们是通过redis#setnx实现的。这里我们就无法通过他统一记录了。我们应该加上更小的时间单元存储到一个集合汇总。然后根据集合的总量计算限流。redis的zsett数据结构就和符合我们的需求。
  • 为什么选择zset呢,因为redis的zset中除了值以外还有一个权重。会根据这个权重进行排序。如果我们将我们的时间单元及时间戳作为我们的权重,那么我们获取统计的时候只需要按照一个时间戳范围就可以了。
  • 因为zset内元素是唯一的,所以我们的值采用uuid或者雪花算法一类的id生成器
// 滑动时间窗口算法
    @GetMapping("/startList")
    public Map<String, Object> startList(@RequestParam Map<String, Object> paramMap) {
        String redisKey = "qpsZset";
        Integer times = 100;
        if (paramMap.containsKey("times")) {
            times = Integer.valueOf(paramMap.get("times").toString());
        }
        long currentTimeMillis = System.currentTimeMillis();
        long interMills = 10000L;
        Long count = redisTemplate.opsForZSet().count(redisKey, currentTimeMillis - interMills, currentTimeMillis);
        // 检查QPS(Queries Per Second)是否超过限制
        /**
         * 使用System.currentTimeMillis()获取当前时间戳。
         * 设置一个时间间隔interMills为1000毫秒(即1秒)。
         * 使用redisTemplate.opsForZSet().count(redisKey, currentTimeMillis - interMills, currentTimeMillis)查询过去1秒内Redis ZSet中指定键(redisKey)的数量。这个数量会被赋值给count变量。
         * 如果count的值大于times,则抛出一个运行时异常,表示QPS超过限制
         */
        if (count > times) {
            throw new RuntimeException("qps refuse request");
        }
        redisTemplate.opsForZSet().add(redisKey, UUID.randomUUID().toString(), currentTimeMillis);
        Map<String, Object> map = new HashMap<>();
        map.put("success", "success");
        return map;
    }

在这里插入图片描述

漏桶算法

漏桶算法是一种常用于流量控制和限流的算法,其核心思想是将突发流量整形以便为网络提供一个稳定的流量。

漏桶算法可以看作是一个带有常量服务时间的单服务器队列,如果漏桶(包缓存)溢出,那么数据包会被丢弃。在网络中,漏桶算法可以控制端口的流量输出速率,平滑网络上的突发流量,实现流量整形,从而为网络提供一个稳定的流量。

漏桶算法的实现相对简单,不需要复杂的数据结构或计算,易于理解和部署。其优点包括平滑处理流入系统的请求,以恒定的速率将请求处理释放,从而避免了突发请求对系统的冲击;控制精度高,可以通过调整漏桶的出水速率来精确地控制请求的处理速度;适用于需要平滑处理流量和避免突发请求的场景,例如网络流量控制、防止DDOS攻击等。

然而,漏桶算法也存在一些缺点,例如请求延迟,可能导致某些请求的响应时间变长;不适用于实时性要求高的场景,因为请求需要按照恒定速率进行处理,无法满足即时性要求;无法应对突发流量,因为漏桶的出水速率是固定的,无法根据流量的变化进行动态调整。

在这里插入图片描述

优点

  • 面对限流更加的柔性,不在粗暴的拒绝。
  • 增加了接口的接收性
  • 保证下流服务接收的稳定性。均匀下发

实现

    // 漏桶算法
    @GetMapping("/startLoutong")
    public Map<String, Object> startLoutong(@RequestParam Map<String, Object> paramMap) {
        String redisKey = "qpsList";
        Integer times = 100;
        if (paramMap.containsKey("times")) {
            times = Integer.valueOf(paramMap.get("times").toString());
        }
        Long size = redisTemplate.opsForList().size(redisKey);
        // 检查队列长度是否超过限制
        if (size >= times) {
            throw new RuntimeException("qps refuse request");
        }
        // 添加请求到队列Redis列表的右侧。
        Long aLong = redisTemplate.opsForList().rightPush(redisKey, String.valueOf(paramMap));
        if (aLong > times) {
            //为了防止并发场景。这里添加完成之后也要验证。  即使这样本段代码在高并发也有问题。此处演示作用
            // 修剪Redis列表,使其长度为times
            redisTemplate.opsForList().trim(redisKey, 0, times - 1);
            throw new RuntimeException("qps refuse request");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("success", "success");
        return map;
    }

模拟消费

@Component
@Slf4j
public class SchedulerTask {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Scheduled(cron = "*/5 * * * * ?")
    private void process() {
        //一次性消费两个
        log.info("正在消费。。。。。。");
        String redisKey = "qpsList";
        redisTemplate.opsForList().trim(redisKey, 2, -1);
    }

}

测试

在这里插入图片描述

令牌桶算法

  • 令牌桶和漏桶法是一样的。只不过将桶的作用方向改变了一下。
  • 漏桶的出水速度是恒定的,如果流量突然增加的话我们就只能拒绝入池
  • 但是令牌桶是将令牌放入桶中,我们知道正常情况下令牌就是一串字符当桶满了就拒绝令牌的入池,但是面对高流量的时候正常加上我们的超时时间就留下足够长的时间生产及消费令牌了。这样就尽可能的不会造成请求的拒绝
  • 最后,不论是对于令牌桶拿不到令牌被拒绝,还是漏桶的水满了溢出,都是为了保证大部分流量的正常使用,而牺牲掉了少部分流量

实现

    // 令牌桶算法
    @GetMapping("/startLingpaitong")
    public Map<String, Object> startLingpaitong(Map<String, Object> paramMap) {
        String redisKey = "lingpaitong";
        String token = redisTemplate.opsForList().leftPop(redisKey);
        //正常情况需要验证是否合法,防止篡改
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("令牌桶拒绝");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("success", "success");
        return map;
    }

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

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

相关文章

【大厂AI课学习笔记】【2.2机器学习开发任务实例】(3)数据准备和数据预处理

项目开始&#xff0c;首先要进行数据准备和数据预处理。 数据准备的核心是找到这些数据&#xff0c;观察数据的问题。 数据预处理就是去掉脏数据。 缺失值的处理&#xff0c;格式转换等。 延伸学习&#xff1a; 在人工智能&#xff08;AI&#xff09;的众多工作流程中&#…

2024.02.18作业

1. 使用fgets统计给定文件的行数 #include <stdio.h> #include <stdlib.h> #include <string.h>int main(int argc, char const *argv[]) {if (argc ! 2){puts("input file error");puts("usage:./a.out filename");return -1;}FILE* f…

单片机学习笔记---AD/DA工作原理(含运算放大器的工作原理)

目录 AD/DA介绍 硬件电路模型 硬件电路 运算放大器 DA原理 T型电阻网络DA转换器 PWM型DA转换器 AD原理 逐次逼近型AD转换器 AD/DA性能指标 XPT2046 XPT2046时序 AD/DA介绍 AD&#xff08;Analog to Digital&#xff09;&#xff1a;模拟-数字转换&#xff0c;将模拟…

【MySQL】学习多表查询和笛卡尔积

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-N8PeTKG6uLu4bJuM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

JMeter接口测试数据分离驱动应用

步骤&#xff1a; 创建csv文件&#xff0c;编写接口测试用例 新建线程组——创建循环控制器&#xff08;循环次数填用例总数&#xff09; 创建CSV数据文件设置&#xff0c;设置参数。&#xff08;注意&#xff1a;是否允许带引号&#xff1f;&#xff1a;一定要设置为true&a…

10M上下文,仅靠提示就掌握一门语言,Google Gemini 1.5被OpenAI抢头条是真冤

这两天&#xff0c;几乎整个AI圈的目光都被OpenAI发布Sora模型的新闻吸引了去。其实还有件事也值得关注&#xff0c;那就是Google继上周官宣Gemini 1.0 Ultra 后&#xff0c;火速推出下一代人工智能模型Gemini 1.5。 公司首席执行官 Sundar Pichai携首席科学家Jeff Dean等众高…

Python输出改变字体颜色方法(附颜色大全)

一、使用示例 print("\033[31m红色字体\033[0m") print("\033[32m绿色字体\033[0m") print("\033[33m黄色字体\033[0m") print("\033[34m蓝色字体\033[0m") print("\033[35m紫色字体\033[0m") print("\033[36m青色字体…

驶向未来:3D可视化模型重塑我们的道路认知

在科技的浪潮中&#xff0c;每一个革新都是对人类未来生活的深度洞察。而今&#xff0c;当可视化这一技术走进我们的视野&#xff0c;它不仅是一场视觉盛宴&#xff0c;更是一次对未来出行方式的全新探索。 一、从平面到立体&#xff0c;解锁道路新视角 你是否曾站在十字路口&…

【Python如何在列表中随机抽出一个元素】

1、python代码如下&#xff1a; import random a [2, 4, 8, 9, "whats up"] q random.choice(a) # 随机从列表a中输出一个元素 b random.choices(a) # 随机从列表a中取出一个元素输出一个列表 lucky_num random.randint(1, 50) # 随机从1-50中取出一个整数包…

解释 OpenAI Sora 的时空补丁:关键因素

人工智能如何将静态图像转换为动态、逼真的视频&#xff1f;OpenAI 的 Sora 通过创新地使用时空补丁来引入答案。 在快速发展的生成模型领域&#xff0c;OpenAI 的 Sora 脱颖而出&#xff0c;成为一个重要的里程碑&#xff0c;有望重塑我们对视频生成的理解和能力。我们解读了…

【简洁的代码永远不会掩盖设计者的意图】如何写出规范整洁的代码

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…

黑马程序员——移动Web——day04

目录&#xff1a; vw适配方案 vw和vh基本使用vw布局vh问题综合案例-酷我音乐 准备工作头部布局头部内容搜索区域banner区域标题公共样式排行榜内容推荐歌单布局推荐歌单内容下载区域头部固定 1.vw适配方案 vw和vh基本使用 vw和vh是相对单位&#xff0c;相对视口尺寸计算结果…

【数据结构】图的存储与遍历

图的概念 图是由顶点集合及顶点间的关系组成的一种数据结构&#xff1a;G (V&#xff0c; E) 图分为有向图和无向图 在有向图中&#xff0c;顶点对<x, y>是有序的&#xff0c;顶点对<x&#xff0c;y>称为顶点x到顶点y的一条边(弧)&#xff0c;<x, y>和&l…

C++学习:list

1.list的定义和结构 list的使用频率不高&#xff0c;在做题时几乎遇不到需要使用list的情景。list是一种双向链表容器&#xff0c;它是标准模板库(STL)提供的一种序列容器。list容器以节点(node的形式存储元素&#xff0c;并使用指针将这些节点链接在一起&#xff0c;形成一个…

【快速解决】python项目打包成exe文件——vscode软件

目录 操作步骤 1、打开VSCode并打开你的Python项目。 2、在VSCode终端中安装pyinstaller&#xff1a; 3、运行以下命令使用pyinstaller将Python项目打包成exe文件&#xff1a; 其中your_script.py是你的Python脚本的文件名。 4、打包完成后&#xff0c;在你的项目目录中会…

如何通过软文引起用户共鸣,媒介盒子支招

不管是哪个行业&#xff0c;哪个品牌都需要通过软文来吸引用户&#xff0c;一篇合格的软文应该能引起用户情绪&#xff0c;让用户为情绪买单&#xff0c;引起用户的共鸣&#xff0c;今天媒介盒子就来和大家聊聊&#xff1a;如何通过软文引起用户共鸣。 一、 熟知用户心理情绪 …

开源软件:推动软件行业繁荣的力量

文章目录 &#x1f4d1;引言开源软件的优势分析开放性与透明度低成本与灵活性创新与协作 开源软件对软件行业的影响推动技术创新和进步促进软件行业的合作与交流培养人才和提高技能促进软件行业的可持续发展 结语 &#x1f4d1;引言 随着信息技术的飞速发展&#xff0c;软件已经…

力扣热题100_双指针_11_盛最多水的容器

文章目录 题目链接解题思路解题代码 题目链接 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回…

洛谷P5716 月份天数 题解

#题外话&#xff08;第31篇题解&#xff09;&#xff08;累了&#xff0c;歇会……&#xff09; #先看题目 题目链接https://www.luogu.com.cn/problem/P5716 #思路&#xff08;看代码&#xff09; #代码 代码1&#xff1a;不管三七二十七&#xff0c;直接先判断闰年&#x…

网络原理 - HTTP/HTTPS(1)

HTTP HTTP是什么 HTTP("全程超文本协议")是一种应用非常广泛的应用层协议. 文本:字符串(能在utf8/gbk)码表上找到合法字符. 超文本:不仅是字符串,还能携带图片啥的(HTML). 富文本:类似于word文档这种. HTTP诞生于1991年.目前已经发展为最主流使用的一种应用层协议.…