复述和Lua实现分布式限流器

  介绍

本篇文章为大家展示了复述和Lua实现分布式限流器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

<强>原理

计数器算法是指在一段窗口时间内允许通过的固定数量的请求,比如10次/秒,500次/30秒。

如果设置的时间粒度越细,那么限流会更平滑。

<>强实现

所使用的Lua脚本

),计数器限流   ——,此处支持的最小单位时间是秒,,若将,expire 改成,pexpire 则可支持毫秒粒度。   ——,键[1],string 限流的关键   ——,ARGV [1], int ,限流数   ——,ARGV [2], int ,单位时间(秒)      local  cnt =,当时(redis.call (“incr",,键[1]))      if  (cnt ==, 1),   ,——cnt 值为1说明之前不存在该值,,因此需要设置其过期时间   ,redis.call (“expire",键[1],,,当时(ARGV [2]))   elseif  (cnt 祝辞,当时(ARGV [1])),   return  1   最终获得;      return 问

返回1表示超过限流,否则返回当前单位时间已通过的请求数

键可以但不限于以下的情况

<李>

ip +接口

<李>

user_id +接口

优点

<李>

实现简单

缺点

<李>

粒度不够细的情况下,会出现在同一个窗口时间内出现双倍请求数

注意

<李>

尽量保持时间粒度精细

<>强场景分析

。1000/3s的限流

<强>极端情况1:

第1秒请求数10

第2秒请求数10

第3秒请求数980

第4秒请求数900

第5秒请求数100

第6秒请求数0

此时注意第3 ~ 5秒内的总请求数高达1980

<强>极端情况2:

第1秒请求数1000

第2秒请求数0

第3秒请求数0

此时后续的第2 ~ 3秒会出现大量拒绝请求

<强>令牌桶模式

<强>原理

复述和Lua实现分布式限流器

令牌桶的

<李>

桶中保存有令牌,存在上限,且一开始是满的

<李>

每次请求都要消耗令牌(可根据不同请求消耗不同数量的令牌)

<李>

每隔一段时间(固定速率)会往桶中放令牌

桶的实现还分为:

可预消费

提前预支令牌数:前人挖的坑,后人跳

不可预消费

令牌数不够直接拒绝

<强>实现

此处实现的不可预消费的令牌桶,具体Lua代码:

——,令牌桶限流:,不支持预消费,,初始桶是满的   ——,键[1],string 限流的关键      ——,ARGV [1], int ,桶最大容量   ——,ARGV [2], int ,每次添加令牌数   ——,ARGV [3], int ,令牌添加间隔(秒)   ——,ARGV [4], int ,当前时间戳      local  bucket_capacity =,当时(ARGV [1])   local  add_token =,当时(ARGV [2])   local  add_interval =,当时(ARGV [3])   local 你=,当时(ARGV [4])      ——,保存上一次更新桶的时间的关键   local  LAST_TIME_KEY =,键[1]. .“_time",,,,   ——,获取当前桶中令牌数   local  token_cnt =, redis.call (“get",,键[1]),   ——,桶完全恢复需要的最大时长   local  reset_time =, math.ceil(时间/bucket_capacity  add_token), *, add_interval;      if  token_cnt  then ,,令牌桶存在   ,——上一次更新桶的时间   ,local  last_time =, redis.call(& # 39;得到# 39;,,LAST_TIME_KEY)   ,——恢复倍数   ,local  multiple =, math.floor((你安康;last_time),/, add_interval)   ,——恢复令牌数   ,local  recovery_cnt =, multiple  * add_token   ,,确保不超过桶容量   ,local  token_cnt =, math.min (bucket_capacity, token_cnt  +, recovery_cnt),安康;1   ,   ,if  token_cnt  & lt; 0,那么   return 才能;1;   ,结束   ,   ,——重新设置过期时间,,避免关键过期   ,redis.call(& # 39;集# 39;,,键[1],token_cnt,, & # 39;前任# 39;,,reset_time),,,,,,   ,redis.call(& # 39;集# 39;,,LAST_TIME_KEY,, last_time  +, multiple  *, add_interval,, & # 39;前任# 39;,,reset_time)   return  token_cnt   ,   else ,,令牌桶不存在=,,token_cnt  bucket_capacity 作用;1   ,,设置过期时间避免钥匙一直存在   ,redis.call(& # 39;集# 39;,,键[1],token_cnt,, & # 39;前任# 39;,,reset_time);   ,redis.call(& # 39;集# 39;,,LAST_TIME_KEY,,现在,,& # 39;前任# 39;,,reset_time  +, 1),,   ,return  token_cnt    

复述和Lua实现分布式限流器