介绍
本篇文章为大家展示了复述和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代码:
——,令牌桶限流:,不支持预消费,,初始桶是满的 ——,键[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实现分布式限流器