首页 > 数据库 >redis通过滑动窗口实现限流

redis通过滑动窗口实现限流

时间:2024-08-04 21:39:07浏览次数:12  
标签:窗口 String redis 限流 key 滑动 请求

一、什么是滑动窗口限流
滑动窗口限流是一种流量控制策略,用于控制在一定时间内允许执行的操作数量或请求频率。它的工作方式类似于一个滑动时间窗口,对每个时间窗口的请求数量进行计数,并根据预先设置的限流策略来限制或调节流量,通常包括以下几个要素:

时间窗口:限流的时间段,例如每秒、每分钟或每小时,窗口可以固定,也可以动态调整。

滑动窗口:在整个事件窗口内滑动的小窗口,用于计算当前时间段内的请求数量。

计数器:用于记录当前窗口内的请求数量数量。

限流策略:预先设定的限流规则,例如允许的最大请求数量,以及如何处理超出限制的请求(例如拒绝、延迟处理)等。

ps:目前主流的限流算法有令牌(Gateway、Ratelimiter)、漏桶(Nginx)、滑动窗口(Sentinel)。

二、为什么需要限流
防止滥用:通过限制每个用户或IP地址的请求频率,可以防止恶意用户或攻击者对系统进行滥用,例如DOS攻击。

防止过载:当大量请求同时到达系统时,如果系统无法合理地处理这些请求,可能会导致系统资源被耗尽,甚至崩溃。

三、工作原理
假设我们时间窗口设为每分钟,那么红色窗口内的时间段就是滑动窗口,如下图:

 

当时间窗口移动时,需要把上一个时间段中的请求数量给减掉,当有新请求或操作进来时,系统会检查窗口内的计数是否已满,如果没满,请求允许执行,反之触发限流策略,比如被拒绝或者进入等待队列。

就拿上图举个例子,当前时间为12:00,计数器为200个,也就是每分钟允许的请求数量为200个,当12点零59秒第201个请求进来了,那么会直接触发限流策略。假设到了12点一分零1秒,系统会把12点至12点零一分的请求数量给移除。

四、Redis实现滑动窗口限流
在Redis中,我们可以用ZSET来实现这个功能。

key可以为请求的资源名,例如根据ip限制访问资源流量,那么key就可以设置为资源名+ip地址,score为当前请求的时间戳,member建议用请求详情的hash进行存储(或者UUID、MD5),避免在并发时,时间戳一致出现score和member一样导致的幂等问题。

代码如下:

public class LimitWindows {
//计数器
private final static long limit = 100;
public boolean allowRequest(Jedis jedis,String key){
//当前时间
long currentTime = System.currentTimeMillis();
//窗口开始时间:当前时间-60s
long windowStart = System.currentTimeMillis() - 60*1000;
//删除窗口开始时间之前的所有数据
jedis.zremrangeByScore(key,"-inf",String.valueOf(windowStart));
//计算总请求数
long current = jedis.zcard(key);
//判断
if(current<limit){
//窗口足够则把当前请求加入
jedis.zadd(key,currentTime,String.valueOf(currentTime));
return true;
}
return false;
}
}

以上高并发下可能会出现原子性问题,那么我们可以考虑用LUA脚本实现:

public class LimitWindows {
//计数器
private final static long limit = 100;
public boolean allowRequest(Jedis jedis,String key){
//获取当前时间戳
long currentTime = 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(currentTime), String.valueOf(limit), String.valueOf(60));
return (long) result == 1;
}
}
ps:"-inf"在reids中表示负无穷,"+inf"表示正无穷

标签:窗口,String,redis,限流,key,滑动,请求
From: https://www.cnblogs.com/azwz/p/18342241

相关文章

  • redis
    redis安装目录规划:###redis下载目录/data/soft/[###redis安装目录/opt/redis_cluster/redis{PORT}/{conf,logs,pid}###redis数据目录/data/redis_cluster/redis{PORT}/redis{PORT}.rdb###redis运维脚本/root/scripts/redisshell.sh安装命令:编辑hosts......
  • 【LeetCode:3. 无重复字符的最长子串 + 滑动窗口】
    ......
  • redis+xxl-job初步设计点赞功能
    一般情况下点赞业务涉及以下下几个方面:1.我们肯定要知道一个题目被多少人点过赞,还要知道,每个人他点赞了哪些题目。2.点赞的业务特性,频繁。用户一多,时时刻刻都在进行点赞,收藏等等处理,如果说我们采取传统的数据库的模式啊,这个交互量是非常大的,很难去抗住这个并发问题,所以我们......
  • Redis 批量删除键
    Redis批量删除键1.简介在Redis中批量优雅的删除大量键是一个很麻烦的问题,下面例举常用的方法和优缺点。2.keys+del命令使用keys使用查找所有匹配的键,然后在使用del一起批量删除。优点操作简单。缺点查找性能特别差,需要遍历所有键。如果rediskey特别多,还有可能造......
  • 【Redis 进阶】哨兵 Sentinel(重点理解流程和原理)
    Redis的主从复制模式下,一旦主节点由于故障不能提供服务,需要人工进行主从切换,同时大量的客户端需要被通知切换到新的主节点上,对于上了一定规模的应用来说,这种方案是无法接受的,于是Redis从2.8开始提供了RedisSentinel(哨兵)加个来解决这个问题。一、基本概念由于对Red......
  • redis缓存雪崩
    Redis缓存雪崩是指在短时间内大量缓存数据同时失效,导致原本应该由缓存承担的请求流量突然涌向后端数据库或其他数据源,从而给后端系统带来巨大压力,可能导致数据库超负荷甚至崩溃的现象。 缓存雪崩通常发生在以下几种情况:-大量数据设置了相同的过期时间,在同一时刻失效。-......
  • Redis - Smembers性能优化
    命令概述SMembers命令用于获取一个集合的所有成员。它的语法如下:SMEMBERSkey其中,key是集合的名称。SMembers命令返回一个包含所有集合成员的数组。如果集合不存在,返回空数组。关键因素内存占用:Redis是内存数据库,因此集合的大小直接影响到内存使用量。网络传输:当使用S......
  • RabbitMQ高级特性 - 消息分发(限流、负载均衡)
    文章目录RabbitMQ消息分发概述如何实现消费分发机制(限制每个队列消息数量)使用场景限流背景实现demo非公平发送(负载均衡)背景实现demoRabbitMQ消息分发概述RabbitMQ的队列在有多个消费者订阅时,默认会通过轮询的机制将消息分发给不同的消费者,但是有些消费者......
  • Java通过redis实线多线程多用户操作时添加锁
    背景由于项目中多出涉及同步数据,同步过程就是从设备上查询数据,将数据库中该设备数据删除,将新数据导入到数据库;多次同步数据或多用户操作,会导致数据库出现重复数据,例如,两个线程同时删除设备数据,同时导入数据,就会出现双倍数据;还有线程1正在导入数据,中途线程2将线程1导入数据之前删......
  • Caused by: io.lettuce.core.RedisCommandExecutionException: WRONGTYPE Operation a
    当遇到io.lettuce.core.RedisCommandExecutionException:WRONGTYPEOperationagainstakeyholdingthewrongkindofvalue这个异常时,说明你在Redis中尝试执行的操作与存储在特定键中的数据类型不匹配。下面是一些具体的步骤来帮助你解决问题:1.确定键的数据类型首先,你......