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();
            //窗口开始时间为当前时间戳减去60s
            long 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 返回false
            return false;
        }
    
        /**
         * 上面的方法可以改写为使用lua脚本,以避免高并发情况下的原子性问题
         */
        public boolean allowVIsitUseLua() {
            //获取当前时间戳
            long nowTimeStamp = System.currentTimeMillis();
            String luaScript = """
                        local window_start_time = ARGV[1] -ARGV[3]*1000
                        redis.call('ZREMRANGEBYSCORE',KEYS[1],'-inf',window_start_time)
                        local now_request = redis.call('ZCARD',KEYS[1])
                        if now_request < tonumber(ARGV[2]) then
                             redis.call('ZADD',KEYS[1],ARGV[1],ARGV[1])
                             return 1
                        else
                             return 0
                        end
                    """;
            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服务。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker 仓库管理

Docker 仓库管理 仓库&#xff08;Repository&#xff09;是集中存放镜像的地方。以下介绍一下 Docker Hub。当然不止 docker hub&#xff0c;只是远程的服务商不一样&#xff0c;操作都是一样的。 Docker Hub 目前 Docker 官方维护了一个公共仓库 Docker Hub。 大部分需求…

Oracle命令大全

文章目录 1. SQL*Plus命令&#xff08;用于连接与管理Oracle数据库&#xff09;2. SQL数据定义语言&#xff08;DDL&#xff09;命令3. SQL数据操作语言&#xff08;DML&#xff09;命令4. PL/SQL程序块5. 系统用户管理6. 数据备份与恢复相关命令1. SQL*Plus命令&#xff08;用…

java-log4j日志冲突解决

一、概述 java日志框架较多&#xff0c;其中主流的slf4j和commons-logging是日志接口&#xff0c;log4j、log4j2和logback是真正的日志实现库。 二、具体库单独使用 2.1 log4j <dependency><groupId>log4j</groupId><artifactId>log4j</artifa…

CentOS stream 9配置网卡

CentOS stream9的网卡和centos 7的配置路径&#xff1a;/etc/sysconfig/network-scripts/ifcfg-ens32不一样。 CentOS stream 9的网卡路径&#xff1a; /etc/NetworkManager/system-connections/ens32.nmconnection 方法一&#xff1a; [connection] idens32 uuid426b60a4-4…

【鸿蒙4.0】详解harmonyos开发语言ArkTS

文章目录 一.什么是ArkTS&#xff1f;1.ArkTS的背景2.了解js&#xff0c;ts&#xff0c;ArkTS的演变js(Javascript)Javascript的简介Javascript的特点 ts(Typescript)ArkTS 二. ArkTS的特点 一.什么是ArkTS&#xff1f; 1.ArkTS的背景 如官方文档所描述&#xff0c;ArkTS是基…

《Linux C编程实战》笔记:Linux信号介绍

信号是一种软件中断&#xff0c;它提供了处理一种异步事件的方法&#xff0c;也是进程惟一的异步通信方式。在Linux系统中&#xff0c;根据POSIX标准扩展的信号机制&#xff0c;不仅可以用来通知某进程发生了什么事&#xff0c;还可以给进程传递数据。 信号的来源 信号的来源…

广东金牌电缆:法大大电子合同助力业务风险管控

广东金牌电缆集团股份有限公司&#xff08;以下简称“广东金牌电缆”&#xff09;成立于2013年&#xff0c;现为广东省电线电缆重点生产企业、广东省守合同重信用单位、国家专精特新小巨人企业、国家高新技术企业&#xff0c;拥有自主商标“夺冠”&#xff0c;“夺冠”商标被评…

一文读懂「Fine-tuning」微调

一、什么是微调&#xff1f; 1. 什么是微调&#xff1f; 微调是指在预训练模型&#xff08;Pre-trained model&#xff09;的基础上&#xff0c;针对特定任务或数据领域&#xff0c;对部分或全部模型参数进行进一步的训练和调整&#xff08;Fine Tune&#xff09;。预训练模型…

File 类的用法和 InputStream, OutputStream 的用法

1.File类的用法 下面就用几个简单的代码案例来熟悉File类里面函数的用法&#xff1a; public class IODemo1 {public static void main(String[] args) throws IOException {File f new File("./test2.txt");//File f new File("C:/User/1/test.txt");S…

redis数据安全(二)数据持久化 RDB

目录 一、RDB快照持久化 原理 二、RDB快照持久化配置&#xff08;redis.conf&#xff09;&#xff1a; 三、触发RDB备份&#xff1a; 1、自动备份&#xff0c;需配置备份规则&#xff1a; 2、手动执行命令备份&#xff08;save | bgsave&#xff09;&#xff1a; 3、flus…

排序:非递归的归并排序

目录 递归与非递归的思想对比&#xff1a; 递归&#xff1a; 非递归&#xff1a; 代码解析&#xff1a; 完整代码&#xff1a; 递归与非递归的思想对比&#xff1a; 递归&#xff1a; 在之前的归并排序&#xff0c;它的核心思想是通过不断的分割&#xff0c;从一个数组变…

JAVA实现向Word模板中插入Base64图片和数据信息

目录 需求一、准备模板文件二、引入Poi-tl、Apache POI依赖三、创建实体类&#xff08;用于保存向Word中写入的数据&#xff09;四、实现Service接口五、Controller层实现 需求 在服务端提前准备好Word模板文件&#xff0c;并在用户请求接口时服务端动态获取图片。数据等信息插…

数据结构图算法

算法就要多练,我在国庆节放假的时间编写了图的算法题,写完让我受益匪浅,希望可以帮助到大家. 文章目录 前言 一、图的数据结构 1.图的邻接表数据结构定义 2.图的邻接矩阵的存储形式 二、邻接表建立图代码 三、邻接表删除边(基本操作考试不考) 四、邻接表删除顶点及销毁整…

【LLM】Prompt微调

Prompt 在机器学习中&#xff0c;Prompt通常指的是一种生成模型的输入方式。生成模型可以接收一个Prompt作为输入&#xff0c;并生成与该输入相对应的输出。Prompt可以是一段文本、一个问题或者一个片段&#xff0c;用于指导生成模型生成相应的响应、续写文本等。 Prompt优化…

.pings勒索病毒的无声侵袭:保护你的数据财产免受.pings的侵害

尊敬的读者&#xff1a; 在数字时代&#xff0c;网络犯罪者不断推陈出新&#xff0c;而.pings勒索病毒则是一种极富威胁的加密型恶意软件。本文将深入探讨.pings勒索病毒的攻击方式&#xff0c;为您提供从数据恢复到全面预防的完整指南&#xff0c;帮助您有效对抗这一威胁。如…

安全帽识别:智能监控新趋势

在现代工业安全领域&#xff0c;安全帽识别技术已成为一项关键的创新。这项技术通过智能监控系统确保工作人员在危险环境中佩戴安全帽&#xff0c;显著提升了工作场所的安全标准。本文将探讨这一技术的工作原理、应用前景及其在现代工业中的重要性。 安全帽识别的工作机制 安全…

【漏洞攻击之文件上传条件竞争】

漏洞攻击之文件上传条件竞争 wzsc_文件上传漏洞现象与分析思路编写攻击脚本和重放措施中国蚁剑拿flag wzsc_文件上传 漏洞现象与分析 只有一个upload前端标签元素&#xff0c;并且上传任意文件都会跳转到upload.php页面&#xff0c;判定是一个apache容器&#xff0c;开始扫描…

什么是车载信息娱乐系统和集成驾驶舱

什么是车载信息娱乐系统(IVI)? “车载信息娱乐(IVI)”通过向驾驶员和乘客提供信息和娱乐&#xff0c;为驾驶提供便利和舒适。为了理解这个概念&#xff0c;有必要知道“信息娱乐”的含义。“信息娱乐”是这个市场中使用的一个词&#xff0c;它结合了“信息”和“娱乐”两个词…

「达摩院MindOpt」优化形状切割问题(MILP)

1. 形状切割问题 在制造业&#xff0c;高效地利用材料不仅是节约成本的重要环节&#xff0c;也是可持续发展的关键因素。无论是在金属加工、家具制造还是纺织品生产中&#xff0c;原材料的有效利用都直接影响了整体效率和环境影响。 形状切割问题&#xff08;Shape Cutting o…

区域入侵检测AI边缘计算智能分析网关V4如何通过ssh进行服务器远程运维

智能分析网关V4是一款高性能、低功耗的AI边缘计算硬件设备&#xff0c;它采用了BM1684芯片&#xff0c;集成高性能8核ARM A53&#xff0c;主频高达2.3GHz&#xff0c;并且INT8峰值算力高达17.6Tops&#xff0c;FB32高精度算力达到2.2T&#xff0c;每个摄像头可同时配置3种算法&…