Redis实现滑动窗口限流详解
创作时间:
作者:
@小白创作中心
Redis实现滑动窗口限流详解
引用
CSDN
1.
https://blog.csdn.net/weixin_45433817/article/details/138762093
一、什么是滑动窗口限流
滑动窗口限流是一种流量控制策略,用于控制在一定时间内允许执行的操作数量或请求频率。它的工作方式类似于一个滑动时间窗口,对每个时间窗口的请求数量进行计数,并根据预先设置的限流策略来限制或调节流量,通常包括以下几个要素:
- 时间窗口:限流的时间段,例如每秒、每分钟或每小时,窗口可以固定,也可以动态调整。
- 滑动窗口:在整个事件窗口内滑动的小窗口,用于计算当前时间段内的请求数量。
- 计数器:用于记录当前窗口内的请求数量数量。
- 限流策略:预先设定的限流规则,例如允许的最大请求数量,以及如何处理超出限制的请求(例如拒绝、延迟处理)等。
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"表示正无穷
本文原文来自CSDN
热门推荐
庄园制度瓦解后是什么制度
达格列净降血压效果高吗
装修设计师如何在验房收房时检查房屋结构安全隐患?
装修水电如何验收?这16个注意事项千万别忽略!
A股低价股占比几何?49只个股不足2元,ST股占比近四成
掌握键盘技巧,轻松替代鼠标提升工作效率
等保三级机房标准详解:CCE服务如何满足安全要求?
口腔干燥综合征,你了解多少?
专家解读:如何区分流感、支原体、合胞病毒、腺病毒?
谷氨酰基转移酶偏高的原因及危害
碳水化合物:质量决定体重的奥秘——哈佛大学最新研究解读
从心脏到脑子,这类饮品摧毁了多少姑娘的健康
智商160是什么概念的?
美本毕业生起薪大比拼:高薪专业及顶尖院校大盘点
曲唑酮可以用于抑郁,也可以治疗失眠,使用时要注意什么?
肯尼迪遇刺案真相是啥?为何后来总统都不敢公开白宫资料
刑事案件有分类别吗:从法律视角解读犯罪案件的分类标准与意义
公司员工考勤管理系统怎么优化?
保安证手机查询指南:多种便捷方式快速获取电子版
数独方法及技巧(数独的几种方法技巧)
给初学者的数独规则
江苏南京:报废汽车“变形记”
叔本华的哲学:艺术作为痛苦的解药
我姓张给儿子起名字叫什么?张姓男孩名字参考
红杉资本起诉币安赵长鹏:资本与创业者的法律纠纷
冲调米粉很简单?新手妈妈容易“误操作”,难怪宝宝不爱吃!
消防展厅设计:科技赋能消防安全知识科普
半导体工业超纯水标准及水质颗粒物检测(液体粒子计数器)仪器选型
超纯水的极限电阻率为什么是18.3MΩ*CM?
中国复姓文化:从起源到传承的千年故事