千家信息网

Redis和Lua实现分布式限流器

发表于:2024-11-26 作者:千家信息网编辑
千家信息网最后更新 2024年11月26日,本篇文章为大家展示了Redis和Lua实现分布式限流器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。原理计数器算法是指在一段窗口时间内允许通过的固定数量的请求
千家信息网最后更新 2024年11月26日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秒会出现大量拒绝请求

令牌桶模式

原理

令牌桶的

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

  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安全错误 数据库的锁怎样保障安全 数据库的数据模型用到哪些图 网络安全ctf有哪些人 秦农银行网络安全 怎么登录数据库地址 我的世界摧毁服务器指令 ark方舟服务器辅助 网络安全宣传周活动拉开帷幕 下列不属于非文献型数据库 杭州它山网络技术有限公司 聚力青春守护网络安全总结 杭州应用软件开发项目 南山科技园互联网公司有哪些 导入数据库后修改数据库 ipddr网络安全 衢州电子网络技术怎么样 数据服务器一直重启 北京世联互联网科技有限公司 金仓数据库换授权文件 数据库旁边住人有影响吗 软件开发公司薪酬制度 传奇服务器宠物怎么设置 绝地求生蓝洞更换服务器 暗月网络安全解压密码 锐捷校招软件开发面试流程 小学网络安全宣传教育计划 人工智能企业数据库系统的目的 软件开发语言和框架 神经网络技术路线图模板 数据库插入字段自动更新同步 数字推算软件开发
0