Redis和Lua实现分布式限流器
发表于:2025-02-08 作者:千家信息网编辑
千家信息网最后更新 2025年02月08日,本篇文章为大家展示了Redis和Lua实现分布式限流器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。原理计数器算法是指在一段窗口时间内允许通过的固定数量的请求
千家信息网最后更新 2025年02月08日Redis和Lua实现分布式限流器
本篇文章为大家展示了Redis和Lua实现分布式限流器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
原理
计数器算法是指在一段窗口时间内允许通过的固定数量的请求, 比如10次/秒, 500次/30秒.
如果设置的时间粒度越细, 那么限流会更平滑.
实现
所使用的 Lua 脚本
-- 计数器限流-- 此处支持的最小单位时间是秒, 若将 expire 改成 pexpire 则可支持毫秒粒度.-- KEYS[1] string 限流的key-- ARGV[1] int 限流数-- ARGV[2] int 单位时间(秒)local cnt = tonumber(redis.call("incr", KEYS[1]))if (cnt == 1) then -- cnt 值为1说明之前不存在该值, 因此需要设置其过期时间 redis.call("expire", KEYS[1], tonumber(ARGV[2]))elseif (cnt > tonumber(ARGV[1])) then return -1end return cnt
返回 -1 表示超过限流, 否则返回当前单位时间已通过的请求数
key 可以但不限于以下的情况
ip + 接口
user_id + 接口
优点
实现简单
缺点
粒度不够细的情况下, 会出现在同一个窗口时间内出现双倍请求数
注意
尽量保持时间粒度精细
场景分析
eg. 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代码:
-- 令牌桶限流: 不支持预消费, 初始桶是满的-- KEYS[1] string 限流的key-- ARGV[1] int 桶最大容量-- ARGV[2] int 每次添加令牌数-- ARGV[3] int 令牌添加间隔(秒)-- ARGV[4] int 当前时间戳local bucket_capacity = tonumber(ARGV[1])local add_token = tonumber(ARGV[2])local add_interval = tonumber(ARGV[3])local now = tonumber(ARGV[4])-- 保存上一次更新桶的时间的keylocal LAST_TIME_KEY = KEYS[1].."_time"; -- 获取当前桶中令牌数local token_cnt = redis.call("get", KEYS[1]) -- 桶完全恢复需要的最大时长local reset_time = math.ceil(bucket_capacity / add_token) * add_interval;if token_cnt then -- 令牌桶存在 -- 上一次更新桶的时间 local last_time = redis.call('get', LAST_TIME_KEY) -- 恢复倍数 local multiple = math.floor((now - 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 < 0 then return -1; end -- 重新设置过期时间, 避免key过期 redis.call('set', KEYS[1], token_cnt, 'EX', reset_time) redis.call('set', LAST_TIME_KEY, last_time + multiple * add_interval, 'EX', reset_time) return token_cnt else -- 令牌桶不存在 token_cnt = bucket_capacity - 1 -- 设置过期时间避免key一直存在 redis.call('set', KEYS[1], token_cnt, 'EX', reset_time); redis.call('set', LAST_TIME_KEY, now, 'EX', reset_time + 1); return token_cnt end
令牌桶的关键是以下几个参数:
桶最大容量
每次放入的令牌数
放入令牌的间隔时间
令牌桶的实现不会出现计数器模式中单位时间内双倍流量的问题.
上述内容就是Redis和Lua实现分布式限流器,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。
令牌
时间
单位
情况
粒度
消费
最大
容量
计数器
支持
分布式
限流器
不同
不够
内容
原理
双倍
技能
接口
数量
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
移动无线上网服务器
保定软件开发贺建强
保证网络安全工作
安防 软件开发
楚雄师范图书馆数据库
北京gpu服务器报价
软件开发权需要什么许可证
网络技术与英语高效课堂
俄罗斯的化学数据库技术手册
网络运营者建立网络安全制度
多多果园 是谁软件开发
竞选网络技术部的优势
深圳市鲸蓝互联网科技有限公司
石峰区计算机网络技术
上海大愚互联网科技有限公司
世界技能大赛网络安全冠军
上士网络安全令牌
网络安全ATD
计算机网络技术 ui设计
接交换机后找不到服务器ip
虹口区互联网软件开发咨询热线
最新学校网络安全视频
逆水寒玩家蹲守原服务器氪金大佬
医疗设备网络安全整改报告
上士网络安全令牌
全球恐怖主义数据库怎么使用
怎么把数据插入数据库表里
湖南长城金融软件开发
网络安全知识 视频教程
我的世界未来服务器