redis lua限流算法实现示例


Posted in Redis onJuly 15, 2022

限流算法

常见的限流算法

  • 计数器算法
  • 漏桶算法
  • 令牌桶算法

计数器算法

  顾名思义,计数器算法是指在一定的时间窗口内允许的固定数量的请求.比如,2s内允许10个请求,30s内允许100个请求等等.如果设置的时间粒度越细,那么相对而言限流就会越平滑,控制的粒度就会更细.

场景分析

试想,如果设置的粒度比较粗会出现什么样的问题呢?如下图设置一个 1000/3s 的限流计数统计.

redis lua限流算法实现示例

图中的限流策略为3s内允许的最大请求量为1000,那么会出现2个极端:
 

极端情况1:

  • 第1s请流量为10,  
  • 第2s请流量为10,  
  • 第3s请流量突然激增到980.这意味着在这一刻,有大量的请求蜂拥而至,假设服务每秒能处理的

上线为800/1s,但是此刻却有超过这个量级的请求量,那么后果是不堪设想的.

极端情况2:  

  • 第1s请流量突然就达到990,
  • 留给后续第2s,3s的可请求数量就非常少了,可能会出现大量的拒绝请求.

结论:

如果用统计计数算法,尽量保持粒度切割精细.

算法实现

redis的ttl特性完美的满足了这一需求,将时间窗口设置为key的失效时间,然后将key的值每次请求+1即可.伪代码实现思路:

//1.判断是否存在该key
if(EXIT(key)){
  // 1.1自增后判断是否大于最大值,并返回结果
  if(INCR(key) > maxPermit){
     return false;
  }
 return true;
}
//2.不存在key,则设置key初始值为1,失效时间为3秒
SET(KEY,1);
EXPIRE(KEY,3);

漏铜算法

漏桶算法核心概念:

  • 桶的容量是固定的,并且水流以一个固定的速率流出;
  • 流入的水流可以是任意速率;
  • 如果流入的水流超出了桶的容量,则后续流入的水流溢出(请求被丢弃)。
  • 如果桶内没有水,则不需要流出

redis lua限流算法实现示例

缺点:

不难想象漏桶算法并不能很好的应对突发的流量限制,在某一个时间段流量激增,则漏桶算法处理就比较无能为力.这个时候就需要用到和他相反设计的令牌桶算法

令牌桶算法:

redis lua限流算法实现示例

如上图所示,整个请求流程一目了然.简单概括如下:

1.用户请求资源时首选从桶里获取令牌,如果有令牌则放行,如此同时桶里的令牌数量-1

2.于此同时,以一定的速率往桶里加入令牌,这个速度是可根据实际场景随意设置.

算法实现

var key;
var maxPermit;//桶的容量,即最大请求限制
var expire;//失效时间
var bucketInterval;//每次向桶里添加令牌的时间间隔
var bucketNum;//每次向桶里添加令牌的个数
var lastTimeKey = key +"last";//标记上一次操作时间
//判断是否存在该key
if(EXIT(key)){
  var value = GET(key);
  var diffTime = now() - lastTimeKey;
  // 1.1判断是否超出时间间隔
  if(diffTime  > bucketInterval){
      // 1.2根据时间间隔,计算出应该向桶里添加令牌的个数
      local maxValue = value+math.floor(diff/interval)*step;
      if (maxValue > limit)
         value = limit;
      else
         value = maxValue;
     //设置key的值及操作时间
     SET(key,value);
     SET(lastTimeKey,now());     
  }
  // 2.1在时间间隔内,判断桶里是否有值
  if(value <= 0){
     reurn false;
  }else{
    // 2.2 减1
    DECR(key);
  }
reture true;
}
//2.不存在key,则设置key初始值为maxPermit-1
SET(key,maxPermit-1);
EXPIRE(lastTimeKey,now());

上面实现代码只是伪代码,提供的是一种思路而已. 仔细想来其中某个环节其实并不完美.大家可以参考Guava的ratelimit实现思路,他的限流就是基于令牌桶算法,但是比较遗憾的是在单机下的限流.

思考:  

就是时间间隔如果过长的话,一次性向桶里添加的令牌数量则是桶的最大容量!那么某个时间的瞬间请求过来,服务器的压力是非常大的.

所以此处增加令牌数可以设置的稍微合理些,哪怕间隔时间再长!

以上就是redis lua限流算法实现示例的详细内容,更多关于redis lua限流算法的资料请关注三水点靠木其它相关文章!


Tags in this post...

Redis 相关文章推荐
详解RedisTemplate下Redis分布式锁引发的系列问题
Apr 27 Redis
redis哨兵常用命令和监控示例详解
May 27 Redis
详解Redis复制原理
Jun 04 Redis
Redis Cluster 集群搭建你会吗
Aug 04 Redis
redis缓存存储Session原理机制
Nov 20 Redis
解决Redis启动警告问题
Feb 24 Redis
解决redis批量删除key值的问题
Mar 23 Redis
Redis如何使用乐观锁(CAS)保证数据一致性
Mar 25 Redis
基于Redis6.2.6版本部署Redis Cluster集群的问题
Apr 01 Redis
 Redis 串行生成顺序编码的方法实现
Apr 03 Redis
Grafana可视化监控系统结合SpringBoot使用
Apr 19 Redis
Redis入门基础常用操作命令整理
Jun 01 Redis
Redis Lua脚本实现ip限流示例
Jul 15 #Redis
redis protocol通信协议及使用详解
Jul 15 #Redis
Redis sentinel哨兵集群的实现步骤
Jul 15 #Redis
Redis唯一ID生成器的实现
Jul 07 #Redis
Redis+AOP+自定义注解实现限流
Jun 28 #Redis
利用Redis实现点赞功能的示例代码
Jun 28 #Redis
一文教你快速生成MySQL数据库关系图
Jun 28 #Redis
You might like
关于PHP堆栈与列队的学习
2013/06/21 PHP
php字符集转换
2017/01/23 PHP
PHP基于imagick扩展实现合成图片的两种方法【附imagick扩展下载】
2017/11/14 PHP
Javascript实现页面跳转的几种方式分享
2013/10/26 Javascript
JS使用cookie实现DIV提示框只显示一次的方法
2015/11/05 Javascript
jQuery防止重复绑定事件的解决方法
2016/05/14 Javascript
基于JS实现无缝滚动思路及代码分享
2016/06/07 Javascript
js实现获取两个日期之间所有日期的方法
2016/06/17 Javascript
js中判断变量类型函数typeof的用法总结
2016/08/09 Javascript
JS常见简单正则表达式验证功能小结【手机,地址,企业税号,金额,身份证等】
2017/01/22 Javascript
bootstrap手风琴折叠示例代码分享
2017/05/22 Javascript
javascript完美实现给定日期返回上月日期的方法
2017/06/15 Javascript
javaScript实现鼠标在文字上悬浮时弹出悬浮层效果
2020/04/12 Javascript
微信小程序之多列表的显示和隐藏功能【附源码】
2018/08/06 Javascript
mpvue写一个CPASS小程序的示例
2018/09/04 Javascript
JavaScript面向对象编程小游戏---贪吃蛇代码实例
2019/05/15 Javascript
vue中实现Monaco Editor自定义提示功能
2019/07/05 Javascript
Vue中axios的封装(报错、鉴权、跳转、拦截、提示)
2019/08/20 Javascript
微信小程序跨页面数据传递事件响应实现过程解析
2019/12/19 Javascript
javascript设计模式 ? 职责链模式原理与用法实例分析
2020/04/16 Javascript
Node.js API详解之 querystring用法实例分析
2020/04/29 Javascript
python sys模块sys.path使用方法示例
2013/12/04 Python
Python编程判断一个正整数是否为素数的方法
2017/04/14 Python
Django中针对基于类的视图添加csrf_exempt实例代码
2018/02/11 Python
Python使用post及get方式提交数据的实例
2019/01/24 Python
python 将日期戳(五位数时间)转换为标准时间
2019/07/11 Python
python list数据等间隔抽取并新建list存储的例子
2019/11/27 Python
python图形开发GUI库pyqt5的基本使用方法详解
2020/02/14 Python
利用Vscode进行Python开发环境配置的步骤
2020/06/22 Python
Pycharm 跳转回之前所在页面的操作
2021/02/05 Python
HTML5拖放API实现拖放排序的实例代码
2017/05/11 HTML / CSS
历史学专业个人的自我评价
2013/10/13 职场文书
2014新年寄语
2014/01/20 职场文书
营销与策划专业求职信
2014/06/20 职场文书
小学教师学习党的群众路线教育实践活动心得体会
2014/10/31 职场文书
2016高校自主招生自荐信范文
2016/01/28 职场文书