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.hqwc.cn/news/413815.html

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

相关文章

蓝天采集器,功能逆天的网站数据抓取神器,轻松助你成为采集达人,附带搭建配置文档

源码介绍 蓝天采集器是一款专为web服务器打造的数据采集神器。与市面上常见的桌面端采集工具&#xff08;如火车头等&#xff09;相比&#xff0c;蓝天采集器在易用性、上手成本和灵活性方面更胜一筹。它部署简便&#xff0c;无需复杂的设置&#xff0c;即可迅速融入您的web服…

python统计分析——样本均值的分布(上)

参考资料&#xff1a;用python动手学统计学 1、导入库 import numpy as np import pandas as pd import scipy as sp from scipy import statsfrom matplotlib import pyplot as plt import seaborn as sns 2、设置总体 本次研究总体是均值为4、标准差为0.8的正态总体。 po…

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-热门帖子推荐显示实现

锋哥原创的SpringbootLayui python222网站实战&#xff1a; python222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火…

每日一题——LeetCode1266.访问所有点的最小时间

方法一 个人方法 找规律&#xff1a; 当前的点为current&#xff0c;下一个点为next&#xff0c;x为两点横坐标之间距离&#xff0c;y为两点竖坐标之间距离 1、当两点横坐标相同时&#xff0c;两点距离为y 2、当两点竖坐标相同时&#xff0c;两点距离为x 3、当两点x与y相同…

回归预测 | Matlab实现SSA-BP麻雀算法优化BP神经网络多变量回归预测

回归预测 | Matlab实现SSA-BP麻雀算法优化BP神经网络多变量回归预测 目录 回归预测 | Matlab实现SSA-BP麻雀算法优化BP神经网络多变量回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现SSA-BP麻雀算法优化BP神经网络多变量回归预测&#xff1b; 2.数据…

UML-实现图(组件图和部署图)

实现图是从系统的层次来描述的&#xff0c;描述硬件的组成和布局&#xff0c;描述软件系统划分和功能实现。 UML-实现图&#xff08;组件图和部署图&#xff09; 一、组件图1.组件图的元素&#xff08;1&#xff09;组件&#xff08;2&#xff09;接口&#xff08;3&#xff09…

C++后端笔记

C后端笔记 资源整理一、高级语言程序设计1.1 进制1.2 程序结构基本知识1.3 数据类型ASCII码命名规则变量间的赋值浮点型变量的作用字符变量常变量 const运算符 二、高级语言程序设计&#xff08;荣&#xff09; 资源整理 C后端开发学习路线及推荐学习时间 C基础知识大全 C那…

Flink TaskManager内存管理机制介绍与调优总结

内存模型 因为 TaskManager 是负责执行用户代码的角色&#xff0c;一般配置 TaskManager 内存的情况会比较多&#xff0c;所以本文当作重点讲解。根据实际需求为 TaskManager 配置内存将有助于减少 Flink 的资源占用&#xff0c;增强作业运行的稳定性。 TaskManager 内…

02 MyBatisPlus核心功能之基于Mapper接口CRUD+基于Service接口实现CRUD

项目结构&#xff1a; 1.1 Insert方法 // 插入一条记录 // T 就是要插入的实体对象 // 默认主键生成策略为雪花算法&#xff08;后面讲解&#xff09; //返回值是影响条数 int insert(T entity);1.2 Delete方法 // 根据 entity 条件&#xff0c;删除记录 int delete(Param(…

详解JDBC各个对象

文章目录 DriverManagerConnectionStatementPreparedStatementResultSet案例案例一&#xff1a;JDBC控制事务案例二&#xff1a;SQL 注入错误演示 DriverManager 概述&#xff1a;DriverManager 是驱动管理类 作用 获取数据库连接 // 返回数据库连接的对象&#xff0c;url 是指…

资料收集:储能bms架构

储能系统保护与控制之电池管理系统&#xff08;BMS&#xff09; 重点储能BMS企业汇总 储能BMS分为三级架构&#xff1a; 第一级&#xff1a;每个电池插箱包含1并48串电池模组&#xff0c;插箱配置1个BMU从控模块&#xff0c;用于对该电池组的电压、温度等信息的采集和上传。 …

学习Spring的第五天(Bean的依赖注入)

Bean的依赖注入有两种方式: 一 . 常规Bean的依赖注入 很简单,不过多赘述了,注意ref: 是构造函数或set方法的参数,一般为对象, value: 是构造函数或set方法的参数,一般为值. 看下图 1.1 下面来演示一下集合数据类型的关于Bean的依赖注入 1.1.1这是List的注入(演示泛型为Strin…