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

news2024/9/30 3:21:27

文章目录

      • 前言
      • 什么是滑动窗口
      • 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服务。

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

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

相关文章

从初学者到专家:Dubbo中Application的终极指南【十一】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 从初学者到专家&#xff1a;Dubbo中Application的终极指南【十一】 前言Application组件的重要性Application 在 Dubbo 中的定义Application 的作用和重要性Dubbo 应用程序的生命周期 配置和使用Appli…

往docker中cloudbeaver的容器添加达梦数据库、impala数据库连接支持(cloudbeaver添加自定义数据连接)

cloudbeaver默认没有开放impala连接&#xff0c;更不会支持国产数据库了 docker安装运行cloudbeaver可以参考文章&#xff1a;docker安装运行CloudBeaver并设置默认语言为中文 本文跳过cloudbeaver镜像拉取&#xff0c;直接就开始实现自定义数据库连接功能 1、初始化cloudbe…

卷级实时备份功能特点及应用场景

为满足部分对RTO和RPO指标敏感的用户需求&#xff0c;云祺科技通过结合卷远程复制技术和持续数据保护技术、以及高可用技术的原理&#xff0c;推出了一款基于卷为最小处理单元的实时容灾备份产品&#xff0c;其对于备份源对象具有良好的兼容性&#xff0c;无论是文件、影音、应…

json-server的基础使用

json-server 是什么? 用来快速搭建模拟的 REST API 的工具包 可以30秒内快速为我们搭建一个假的基于 REST API的服务 我们要如何使用呢&#xff1f; 1.先安装 //全局安装 npm i -g json-server 2.创建文件 db.json 我们需要在db.json放入一点内容 放入示例&#xff1a; {/…

带你解析Git的基础功能(三)

文章目录 前言一.远程仓库的概念二.远程仓库的操作2.1新建远程仓库2.2 克隆远程仓库2.3 向远程仓库推送2.4 拉取远程仓库2.5 忽略特殊⽂件2.6 标签管理 三.Git实战场景3.1 Git多人实战场景一准备工作由开发者1和开发者2新增加文件内容。将dev的文件合并到master上总结 3.2 Git多…

TypeScript实现一个贪吃蛇小游戏

游戏效果 文件目录 准备1&#xff1a;新建index.html&#xff0c;编写游戏静态页面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-…

微店商品详情API(micro.item_get)的数据分析和挖掘

随着电商行业的迅猛发展&#xff0c;微店作为电商平台的重要组成部分&#xff0c;提供了丰富的API接口供开发者使用。其中&#xff0c;微店商品详情API&#xff08;micro.item_get&#xff09;是用于获取商品详情的接口&#xff0c;为数据分析和挖掘提供了大量有价值的数据源。…

域环境权限提升

Windows系统配置错误 在Windows系统中&#xff0c;攻击者通常会通过系统内核溢出漏来提权&#xff0c;但是如果碰到无法通过系统内核溢出漏洞法国提取所在服务器权限的情况&#xff0c;就会系统中的配置错误来提权。Windows系统中常见哦欸之错误包括管理员凭证配置错误&#x…

人才测评,招聘软件研发经理的胜任素质模型与任职资格

招聘软件研发经理的胜任素质模型和任职资格是确保能够招聘到胜任的人才的重要组成部分。以下是详细的说明&#xff1a; 一、胜任素质模型 1.技术能力 软件研发经理需要具备深厚的技术能力&#xff0c;对软件开发的各个方面有深入的理解和掌握。他们需要掌握多种编程语言和…

c# 视频播放之Vlc.DotNet.Forms

先说下优缺点 优点&#xff1a;与电脑无关&#xff0c;能播放主流编码格式视频。 缺点&#xff1a;只能播放本地视频&#xff0c;网络视频播放不了。 下面是具体操作和代码 1. 安装Vlc.DotNet.Forms 和 VideoLAN.LibVLC.Windows Vlc.DotNet.Forms 是播放库&#xff0c;Vid…

算法 动态分析 及Java例题讲解

动态规划 动态规划&#xff08;英语&#xff1a;Dynamic programming&#xff0c;简称 DP&#xff09;&#xff0c;是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的&#xff0c;通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适…

Ant Design Vue上传多个图片

模板代码&#xff1a; 定义变量&#xff1a; 文件限制的函数&#xff1a; 上传的函数&#xff1a; 样式函数&#xff1a; 完整代码&#xff1a; <template><div class"dialog-upload" v-if"showUploadDialog"><div class"dialog-uplo…

2018年认证杯SPSSPRO杯数学建模A题(第二阶段)海豚与沙丁鱼全过程文档及程序

2018年认证杯SPSSPRO杯数学建模 基于聚类分析的海豚捕食合作策略 A题 海豚与沙丁鱼 原题再现&#xff1a; 沙丁鱼以聚成大群的方式来对抗海豚的捕食。由于水下光线很暗&#xff0c;所以在距离较远时&#xff0c;海豚只能使用回声定位方法来判断鱼群的整体位置&#xff0c;难…

python|写一个简单的http服务器

本篇文章的python版本为: 什么是http http是一个应用层协议&#xff0c;准确的来说是基于TCP/IP4层网络协议中的传输层中的TCP应用层协议。 额&#xff0c;4层模型大概是这样的: 在网络通信中&#xff0c;用户的数据是以报文来传输的&#xff0c;但是在实际通信中&#xff0…

密码学学习笔记(二十四):TCP/IP协议栈

TCP/IP协议栈的基础结构包括应用层、传输层、网络层、数据链路层和物理层。 应用层 应用层位于TCP/IP协议栈的最顶层&#xff0c;是用户与网络通信的接口。这一层包括了各种高级应用协议&#xff0c;如HTTP&#xff08;用于网页浏览&#xff09;、FTP&#xff08;用于文件传输…

【安全篇 / FortiGuard】(7.4) ❀ 02. 独立VDOM下的FortiGuard服务升级 ❀ FortiGate 防火墙

【简介】由于业务的需要&#xff0c;创建两个独立VDOM&#xff0c;每个VDOM有各自的宽带&#xff0c;但是FortiGuard服务却无法升级&#xff0c;有什么办法解决吗&#xff1f; VDOM概念 首先我们看看什么是VDOM。 ① VDOM将你的FortiGate划分为多个逻辑设备&#xff0c;并将一个…

深入理解Linux文件系统

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;晴る—ヨルシカ 0:20━━━━━━️&#x1f49f;──────── 4:30 &#x1f504; ◀️ ⏸ ▶️ ☰ &…

力扣精选算法100题——长度最小的子数组(滑动窗口专题)

本题链接——长度最小的子数组 第一步&#xff1a;了解题意 给定一个数组&#xff0c;要求在这个数组中找到一个必须是连续的子数组并且这个子数组每个元素加起来>target并从找到的这些数组中取一个最短的数组。 第二步&#xff1a;算法原理 滑动窗口是一种在序列&#xff…

【开源】基于JAVA语言的河南软件客服系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理人员2.2 业务操作人员 三、系统展示四、核心代码4.1 查询客户4.2 新增客户跟进情况4.3 查询客户历史4.4 新增服务派单4.5 新增客户服务费 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的河…

中仕公考:贵州省统一面向社会公开招录公务员公告

2024年1月22日至1月25日期间,每日10:00、14:00及19:00对报名情况进行更新,供报考者参考。 资格初审时间为2024年1月22日9:00至1月28日17:00。 网上缴费时间为2024年1月22日9:00至1月29日17:00。 打印准考证时间2024年3月11日9:00至3月14日17:00。 公共科目笔试时间为: 202…