Redis--Zset使用场景举例(滑动窗口实现限流)

文章目录

      • 前言
      • 什么是滑动窗口
      • zset实现滑动窗口
      • 小结
      • 附录

前言

  • 在Redis–Zset的语法和使用场景举例(朋友圈点赞,排行榜)一文中,提及了redis数据结构zset的指令语法和一些使用场景,今天我们使用zset来实现滑动窗口限流,详见下文。

什么是滑动窗口

  • 滑动窗口是一种流量控制策略,用于控制一定时间内请求的访问数量。

  • 其原理是:将时间划分成规定的时间片段,每个片段有固定的时间间隔,如1s,1min,1h,然后定义一个时间窗口,比如5s,5min等,该窗口会随着时间向右移动。此外还需要计数器计算窗口内的请求数。当窗口移动时,会把已经走过的时间片段的请求数删掉。每当请求进入系统时,会检查计数器中的请求数是否已经满了,如果计数未满,则请求允许被执行;否则执行相应的拒绝方法。

    在这里插入图片描述

  • 滑动窗口在时间内平滑地控制流量,而非简单地固定请求数与速率,可以更加灵活地突发流量和峰值流量。

zset实现滑动窗口

  • 在redis中可以使用zset实现滑动窗口作为限流方案,假如接口A每一分钟只能访问100次,那么我们可以将这个需要限流的接口名作为key,value采用zset数据结构,zset的score设置为当前请求的时间戳,zset的member只需要保证唯一性即可。

  • 涉及到的zset指令

    向zset添加数据:zadd key score member
    删除zset某个score范围内的数据: zremrangebyscore key min max
    统计zset中数据的数量:zcard key

  • 代码实现:在代码中定义滑动窗口大小为"windowSize",收到请求后,在redis生成zset,用zremrangebyscore删除score小于当前时间戳减去"windowSize"的数据,使用zcard查询当前zset中的数据量,即请求量判断是否超出限制值,若超出则不加入zset。

    public class RedisRateLimiter {private Jedis jedis;private String key;//窗口大小private int windowsize;//限制访问的请求数private Integer limitValue;public RedisRateLimiter(Jedis jedis, String key, int windowsize, Integer limitValue) {this.jedis = jedis;this.key = key;this.windowsize = windowsize;this.limitValue = limitValue;}public boolean allowVisit() {//获取当前时间戳long nowTimeStamp = System.currentTimeMillis();//窗口开始时间为当前时间戳减去60slong windowStartTime = nowTimeStamp - windowsize * 1000;//删除score小于窗口开始时间的数据jedis.zremrangeByScore(key, "-inf", String.valueOf(windowStartTime));if (jedis.zcard(key) < limitValue) {jedis.zadd(key, nowTimeStamp, String.valueOf(nowTimeStamp));return true;}//超过limieValue 返回falsereturn false;}/*** 上面的方法可以改写为使用lua脚本,以避免高并发情况下的原子性问题*/public boolean allowVIsitUseLua() {//获取当前时间戳long nowTimeStamp = System.currentTimeMillis();String luaScript = """local window_start_time = ARGV[1] -ARGV[3]*1000redis.call('ZREMRANGEBYSCORE',KEYS[1],'-inf',window_start_time)local now_request = redis.call('ZCARD',KEYS[1])if now_request < tonumber(ARGV[2]) thenredis.call('ZADD',KEYS[1],ARGV[1],ARGV[1])return 1elsereturn 0end""";Object result = jedis.eval(luaScript, 1, key, String.valueOf(nowTimeStamp), String.valueOf(limitValue), String.valueOf(windowsize));return (long) result == 1;}public static void main(String[] args) throws InterruptedException {Jedis jedis = new Jedis("127.0.0.1");String key = "interfaceA";jedis.del(key);RedisRateLimiter interfaceA = new RedisRateLimiter(jedis, key, 60, 10);//调用20次接口观察结果for (int i = 0; i < 20; i++) {System.out.println("当前时间:"+ DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss:SSS").format(LocalDateTime.now())+"接口访问情况: "+(interfaceA.allowVIsitUseLua()?"成功":"失败"));Thread.sleep(1000);}}
    }
    
  • 测试结果:我们在mian方法中,调用20次接口A,设置滑动窗口为60秒内只可以访问10次,观察接口A的访问情况:
    在这里插入图片描述

  • 观察运行结果,因为60秒内该接口只能调用10次,所以调用20次接口A,只有前10次成功了,与我们的期望相同。到此我们通过zset实现了滑动窗口限流的功能。

小结

本文通过Redis的有序集合Zset实现了滑动窗口限流的功能。然而这个方案也存在着缺点,因为zset要记录滑动窗口内的所有接口记录,当我们的要求是某接口在60秒内只能访问100万次,那么我们就可能得存入100万条记录,这种情况下,采用这种方案会消耗很大的存储空间,明显不适用。

附录

  • 在window系统快速使用Redis服务,只需要下载该压缩包 redis压缩包:redis.7z,解压后,找到redis-server.exe即可启动redis服务。

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

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

相关文章

Python高级编程之IO模型与协程

更多Python学习内容&#xff1a;ipengtao.com 在Python高级编程中&#xff0c;IO模型和协程是两个重要的概念&#xff0c;它们在处理输入输出以及异步编程方面发挥着关键作用。本文将介绍Python中的不同IO模型以及协程的概念、原理和用法&#xff0c;并提供丰富的示例代码来帮助…

JavaEE之多线程编程:3. 线程的状态(易懂!)

文章目录 一、关于线程的状态二、观察线程的所有状态1. NEW状态2. TERMINATED状态3. RUNNABLE状态4. TIMED_WAITING 一、关于线程的状态 进程最核心的状态&#xff0c;一个是就绪状态&#xff0c;一个是阻塞状态&#xff08;对于线程同样使用&#xff09;。 以线程为单位进行调…

React入门 - 10(说一说关于 React 的一些理论 )

本章内容 目录 1、React 是一种 ”声明式“开发2、React 可与其他框架并存3、React 的”组件式“开发4、React 遵循”单向数据流“5、React 是一个用于构建”视图层“的框架6、React 采用”函数式编程“ 截止到上一节内容&#xff0c;我们就使用 React实现 TodoList的功能已经…

AOI与AVI:在视觉检测中的不同点和相似点

AOI&#xff08;关注区域&#xff09;和AVI&#xff08;视觉感兴趣区域&#xff09;是视觉检测中常用的两个概念&#xff0c;主要用于识别和分析图像或视频中的特定区域。虽然这两个概念都涉及到注视行为和注意力分配&#xff0c;但它们在定义和实际应用等方面有一些差异。 AOI…

基于SpringBoot的社区帮扶对象管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

视频生成的路线之争:基于LLMs 和 基于SD 的技术路线孰优孰劣?

Diffusion Models视频生成-博客汇总 前言:在 AI 领域,近年来各个子领域都逐渐向 transformer 架构靠拢,只有视觉生成领域一直以 diffusion 结构作为主流方向,但是近年来谷歌、Meta、华为等大厂都在尝试使用基于LLMs的结构完成视觉生成任务。相比于趋于成熟的图像生成任务,…

win10 使用wezterm替代tmux

在windows系统下&#xff0c;没有直接的tmux替代品。wezterm作为一个可高度自定义配置的终端&#xff0c;可以一定程度替代tmux&#xff0c;满足我在windows系统下替换tmux的需求。 配置wezterm&#xff0c;使其快捷键风格接近tmux。快捷键配置如下。基于该配置wezterm.lua&am…

常见的 Linux 发行版和相应的服务管理命令

一、在 Linux 系统中&#xff0c;你可以使用不同的命令来停止服务&#xff0c;具体取决于你的系统和使用的初始化系统&#xff08;init 系统&#xff09;或服务管理工具。以下是一些常见的 Linux 发行版和相应的服务管理命令&#xff1a; 1. 使用 Systemd&#xff08;大多数现…

Git教程学习:03 记录每次更新到仓库

文章目录 1 检查当前文件状态2 跟踪新文件3 暂存已修改的文件4 状态简览5 忽略文件6 查看已暂存和未暂存的修改7 提交更新8 跳过使用暂存区域9 移除文件10 移动文件 现在我们的机器上有了一个 真实项目 的 Git 仓库&#xff0c;并从这个仓库中检出了所有文件的 工作副本。 通常…

windows和linux实时监控文本内容的命令

很多时候我们需要实时查看日志的内容 WIndows Get-Content someFile.txt -WaitLInux tail -f /var/log/apache2/access.logtail命令使用 tail命令是一个用于在Linux和Unix系统中查看文件末尾内容的命令。它通常用于实时监控日志文件的更新&#xff0c;以及查看文件的最新内…

前端和后端之间的CORS 跨域和解决办法

什么是CORS&#xff08;Cross-Origin Resource Sharing&#xff0c;跨源资源共享&#xff09; 跨源资源共享&#xff08;CORS&#xff0c;或通俗地译为跨域资源共享&#xff09;是一种基于 HTTP 头的机制&#xff0c;该机制通过允许服务器标示除了它自己以外的其他源&#xff0…

Docker之安装Nginx

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《Docker之Dockerfile构建镜像》。&#x1f3af;&…

为什么 macOS 比 Windows 稳定?

在计算机操作系统领域&#xff0c;macOS 和 Windows 分别是苹果公司和微软公司的主打产品。尽管两者都拥有大量的用户群体&#xff0c;但在稳定性和用户体验方面&#xff0c;macOS 常常被认为优于 Windows。那么&#xff0c;为什么 macOS 比 Windows 更稳定呢&#xff1f; 我们…

【Python 千题 —— 基础篇】元组的合并

题目描述 题目描述 现在有一个元组 (1, 2, 3, 4),用其它不破坏元组不可破坏性的基础方法上,向元组中添加 6,7,8 这几个数字。 输入描述 无 输出描述 输出“修改”后的元组。 示例 示例 ① 输出: (1, 2, 3, 4, 6, 7, 8)

算法题-爬楼梯-不同思路解法

主要记录个人思考过程&#xff0c;不同方案实现思路的演变 题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;…

你真的知道如何查看 Elasticsearch 的 Debug 日志吗?!

当我们遇到问题或者需要深入了解 Elasticsearch 的运行机制时&#xff0c;调整日志等级&#xff08; logging level &#xff09;到更详细的级别&#xff0c;比如 DEBUG、TRACE &#xff0c;会是一个有效且必须要掌握的方法。 Elasticsearch 提供了如下的接口来支持动态变更 l…

Java中的线程池技术进阶

Java中的线程池技术是用于管理和复用线程的一种技术&#xff0c;它可以有效地提高应用程序的性能和响应速度。在Java中&#xff0c;线程池可以通过java.util.concurrent包中的ExecutorService接口和相关实现类来创建和使用。 以下是一些关于Java线程池技术的进阶知识&#xff…

KY73 合唱队形

动态规划&#xff0c;最长LIS模板&#xff0c;正反各用一次 ti #include<bits/stdc.h>using namespace std;int n; int a[105], dp1[105], dp2[105];int main() {while(cin>>n){memset(a, 0, sizeof(0));memset(dp1, 0, sizeof(dp1));memset(dp2, 0, sizeof(dp2))…

C++系列-第1章顺序结构-9-字符类型char

在线练习&#xff1a; http://noi.openjudge.cn/ https://www.luogu.com.cn/ 总结 本文是C系列博客&#xff0c;主要讲述字符类型char 字符类型char 在C编程语言中&#xff0c;char是一种基本的数据类型&#xff0c;它用于存储单个字符。字符可以是字母、数字、标点符号或者…