Redis实现多种限流算法

一 常见限流算法

1 固定窗口限流

每一个时间段计数器,当计数器达到阈值后拒绝,每过完这个时间段,计数器重置0,重新计数。

优点:实现简单,性能高;

缺点:明显的临界问题,限流不准确;

--KEYS[1]: 限流 key
--ARGV[1]: 阈值
--ARGV[2]: 时间窗口,计数器的过期时间
local rateLimitKey = KEYS[1];
local rate = tonumber(ARGV[1]);
local rateInterval = tonumber(ARGV[2]);local allowed = 1;
-- 每次调用,计数器rateLimitKey的值都会加1
local currValue = redis.call('incr', rateLimitKey);if (currValue == 1) then
--  初次调用时,通过给计数器rateLimitKey设置过期时间rateInterval达到固定时间窗口的目的redis.call('expire', rateLimitKey, rateInterval);allowed = 1;
else
--  当计数器的值(固定时间窗口内) 大于频度rate时,返回0,不允许访问if (currValue > rate) thenallowed = 0;end
end
return allowed

2 滑动日志限流

记录每次请求时间戳,新请求到来后以该时间为时间窗口的结尾统计该时间窗口内请求数是否超过阈值。

优点:没有临界问题,限流较准确;

缺点:记录时间戳内存占用大,每次重新计算请求数,计算性能差;

--KEYS[1]: 限流器的 key
--ARGV[1]: 当前时间窗口的开始时间
--ARGV[2]: 请求的时间戳(也作为score)
--ARGV[3]: rate阈值
--ARGV[4]: 时间间隔
-- 1. 移除时间窗口之前的数据
redis.call('zremrangeByScore', KEYS[1], ARGV[1]-ARGV[4], ARGV[1])
-- 2. 统计当前元素数量
local res = redis.call('zcard', KEYS[1])
-- 3. 是否超过阈值
if (res == nil) or (res < tonumber(ARGV[3])) then-- 4、保存每个请求的时间搓redis.call('zadd', KEYS[1], ARGV[2], ARGV[2])return 1
elsereturn 0
end

3 滑动窗口

3.1普通模式

假设n秒内最多处理b个请求。我们可以将n秒切分成每个大小为m毫秒得时间片。每m毫秒滑动一次窗口,滑动一次统计前n秒各子块请求数之和进而判断当前子块窗口阈值。如1秒内允许通过的请求是200个,但是在这里我们需要把1秒的时间分成多格,假设分成5格(格数越多,流量过渡越平滑),每格窗口的时间大小是200毫秒,每个小窗口中的数字表示在这个窗口中请求数,所以通过观察上图,可知在当前窗口(1000ms-1200毫秒)只要超过110(200-(10+20+50+10))就会被限流。

优点:实现简单,相比较固定窗口,稍微可以降低临界问题;

缺点:临界问题依然存在;

3.2 优化模式

n秒内最多处理b个请求。我们可以将n秒切分成每个大小为m毫秒得时间片,只有最新的时间片内缓存请求和时间戳,之前的时间片内只保留一个请求量的数字。这样可以大大优化存储。例如,如果我们有一个小时费率限制,我们可以为每分钟保留一个计数,并在收到计算限制的新请求时计算过去一小时内所有计数器的总和。

4 漏桶限流

每一个请求到来就会向桶中添加一定的水量,桶底有一个孔,以恒定速度不断的漏出水;当一个请求过来需要向加水时,如果漏桶剩余容积不足以容纳添加的水量,就会触发拒绝策略。漏桶为空,为并发最大情况。

优点:避免激增流量;

缺点:对激增流量反应迟钝,不能高效地利用可用的资源。因为它只在固定的时间间隔放行请求,所以在很多情况下,流量非常低,即使不存在资源争用,也无法有效地消耗资源;实现复杂,内存占用大,性能差;

--参数说明:
--KEYS[1]: 限流器的 key
--ARGV[1]: 容量,决定最大的并发量
--ARGV[2]: 漏水速率,决定平均的并发量
--ARGV[3]: 一次请求的加水量
--ARGV[4]: 时间戳
local limitInfo = redis.call('hmget', KEYS[1], 'capacity', 'passRate', 'addWater','water', 'lastTs')
local capacity = limitInfo[1]
local passRate = limitInfo[2]
local addWater= limitInfo[3]
local water = limitInfo[4]
local lastTs = limitInfo[5]--初始化漏斗
if capacity == false thencapacity = tonumber(ARGV[1])passRate = tonumber(ARGV[2])--请求一次所要加的水量,一定不能大于容量值的addWater=tonumber(ARGV[3])--当前储水量,初始水位一般为0water = addWaterlastTs = tonumber(ARGV[4])redis.call('hmset', KEYS[1], 'capacity', capacity, 'passRate', passRate,'addWater',addWater,'water', water, 'lastTs', lastTs)return 1
elselocal nowTs = tonumber(ARGV[4])--计算距离上一次请求到现在的漏水量 =  流水速度 *  (nowTs - lastTs)local waterPass = tonumber(ARGV[2] *  (nowTs - lastTs))--计算当前剩余水量   =  上次水量  - 时间间隔中流失的水量water = math.max(tonumber(0), tonumber(water - waterPass))--设置本次请求的时间lastTs = nowTs--判断是否可以加水   (容量 - 当前水量 >= 增加水量,判断剩余容量是否能够容纳增加的水量)if capacity - water >= addWater then-- 加水water = water + addWater-- 更新增加后的当前水量和时间戳redis.call('hmset', KEYS[1], 'water', water, 'lastTs', lastTs)return 1end-- 请求失败return 0
end

5 令牌桶限流

我们以恒定速率往令牌桶里加入令牌,令牌桶被装满时,多余的令牌会被丢弃。当请求到来时,会先尝试从令牌桶获取令牌(相当于从令牌桶移除一个令牌),获取成功则请求被放行,获取失败则阻塞或拒绝请求。那么当突发流量来临时,只要令牌桶有足够的令牌,就不会被限流。

优点:可以适应激增流量,通过业务高峰和负载情况调整令牌桶速率,较大利用率下消耗请求;

缺点:实现复杂,占用内存大,性能差。

-- 令牌桶限流算法实现
-- key:限流的key
-- reqTokens:一次请求所需要的令牌数阈值
-- passRate:生成令牌的速率
-- capacity:桶的大小
-- now:当前时间
-- return:0表示限流,1表示放行
local function token_bucket(key, reqTokens, passRate, capacity, now)local current_tokens = tonumber(redis.call('get', key) or '0')local last_refreshed = tonumber(redis.call('get', key .. ':last_refreshed') or '0')local time_passed = math.max(now - last_refreshed, 0)local new_tokens = math.floor(time_passed * passRate)if new_tokens > 0 thenlocal tokens = math.min(current_tokens + new_tokens, capacity)redis.call('set', key, tokens)redis.call('set', key .. ':last_refreshed', now)endif current_tokens < reqTokens thenredis.call('decr', key)return 1elsereturn 0end
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/651920.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有手就行!阿里云上3分钟搞定幻兽帕鲁联机服务器搭建

幻兽帕鲁最近在社区呈现了爆火的趋势&#xff0c;在线人数已突破百万级别&#xff0c;官方服务器也开始出现不稳定&#xff0c;卡人闪退的情况。对于有一定财力的小伙伴&#xff0c;搭建一个私人服务器是一个最稳定而舒服的解决方案。 本文萝卜哥将讲解一下如何快速搭建 palwo…

看图说话:Git图谱解读

很多新加入公司的同学在使用Git各类客户端管理代码的过程中对于Git图谱解读不太理解&#xff0c;我们常用的Git客户端是SourceTree&#xff0c;配合P4Merge进行冲突解决基本可以满足日常工作大部分需要。不同的Git客户端工具对图谱展示会有些许差异&#xff0c;以下是SourceTre…

Java如何对OSS存储引擎的Bucket进行创建【OSS学习】

在前面学会了如何开通OSS&#xff0c;对OSS的一些基本操作&#xff0c;接下来记录一下如何通过Java代码通过SDK对OSS存储引擎里面的Bucket存储空间进行创建。 目录 1、先看看OSS&#xff1a; 2、代码编写&#xff1a; 3、运行效果&#xff1a; 1、先看看OSS&#xff1a; 此…

跟着cherno手搓游戏引擎【12】渲染context和首个三角形

渲染上下文&#xff1a; 目的&#xff1a;修改WindowsWindow的结构&#xff0c;把glad抽离出来 WindowsWindow.h:新建m_Context #pragma once #include "YOTO/Window.h" #include <YOTO/Renderer/GraphicsContext.h> #include<GLFW/glfw3.h> #include…

多种协议转IEC104网关BE110

随着电力系统信息化建设和数字化转型的进程不断加速&#xff0c;对电力能源的智能化需求也日趋增强。健全稳定的智慧电力系统能够为工业生产、基础设施建设以及国防建设提供稳定的能源支持。在此背景下&#xff0c;高性能的工业电力数据传输解决方案——协议转换网关应运而生&a…

03 Redis之命令(基本命令+Key命令+String型Value命令与应用场景)

Redis 根据命令所操作对象的不同&#xff0c;可以分为三大类&#xff1a;对 Redis 进行基础性操作的命令&#xff0c;对 Key 的操作命令&#xff0c;对 Value 的操作命令。 3.1 Redis 基本命令 一些可选项对大小写敏感, 所以应尽量将redis的所有命令大写输入 首先通过 redis-…

Pyecharts水球图全面指南:参数解读、代码实战与高级应用【第41篇—python:Pyecharts水球图】

文章目录 Pyecharts水球图绘制与交互的完整教程1. 简介2. 安装Pyecharts3. 基础水球图4. 自定义水球图样式5. 多水球图展示6. 水球图的动态效果7. 水球图与其他图表的组合8. 数据动态更新与实时展示9. 水球图的交互功能10. 导出水球图为图片或PDF11. 移动端适配 结语 Pyecharts…

S275 4G网络IO模块:智能酒店的理想选择

行业背景 随着物联网技术的发展&#xff0c;酒店服务也变得更加“智能”——自动灯光效果、室内温湿度控制、各种人性化操作等贴心服务&#xff0c;带给顾客真正的宾至如归之感。 同时&#xff0c;智慧酒店更为管理者提供了高效的管理手段&#xff0c;将酒店物耗、能耗、人员…

51-17 视频理解串讲— MViT 论文精读

继TimeSformer模型之后&#xff0c;咱们再介绍两篇来自Facebook AI的论文&#xff0c;即Multiscale Vision Transformers以及改进版MViTv2: Improved Multiscale Vision Transformers for Classification and Detection。 由于本司大模型组最近组织阅读的论文较多&#xff0c;…

解锁一些SQL注入的姿势

昨天课堂上布置了要去看一些sql注入的案例&#xff0c;以下是我的心得&#xff1a; ​​​​​​​ ​​​​​​​ ​​​​​​​ 1.新方法 打了sqli的前十关&#xff0c;我发现一般都是联合查询&#xff0c;但是有没有不是联合查询的方法呢&#xf…

go 实现暴力破解数独

一切罪恶的来源是昨晚睡前玩了一把数独&#xff0c;找虐的选了个最难的模式&#xff0c;做了一个多小时才做完&#xff0c;然后就睡不着了..........程序员不能受这委屈&#xff0c;今天咋样也得把这玩意儿破解了 破解思路&#xff08;暴力破解加深度遍历&#xff09; 把数独…

企业计算机中了360后缀勒索病毒怎么办,360后缀勒索病毒解密流程

企业计算机服务器在生产运营过程中发挥着巨大作用&#xff0c;为企业带来极大便利&#xff0c;存储着企业的重要核心数据&#xff0c;但同时也成为众多勒索病毒攻击的目标。近期&#xff0c;云天数据恢复中心接到很多企业的求助&#xff0c;企业的计算机服务器遭到了360后缀勒索…

大数据学习之Redis、从零基础到入门(一)

目录 一、Redis入门概述 1. 是什么&#xff1f; 官方解释&#xff1a; 2. 能干嘛&#xff1f; 2.1 主流功能与应用 2.1.1分布式缓存 2.1.2内存存储和持久化(RDBAOF) 2.1.3高可用架构搭建 2.1.4缓存穿透、击穿、雪崩 2.1.5分布式锁 2.1.6队列 2.2 总体功能概括 2.3…

【C++干货铺】C++中的IO流和文件操作

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 C语言的输入输出 流是什么&#xff1f; C的IO流 C标准IO流 C文件IO流 文本文件读写 二进制文件的读写 stringstream的简单介绍 将数值类型数据格式化为字…

【GitHub项目推荐--GitHub开源项目排行榜】【转载】

GitHub Ranking GitHub Ranking 是最近 Star 陡增的开源项目&#xff0c;这是一个 GitHub Stars 和 Forks 的排行榜&#xff0c;包含 Github Top 100 Star 的开源项目&#xff0c;根据不同编程语言进行分类&#xff0c;会每天更新。 开源地址&#xff1a;https://github.com/…

【排序算法】C语言实现归并排序,包括递归和迭代两个版本

文章目录 &#x1f680;前言&#x1f680;归并排序介绍及其思想&#x1f680;递归实现&#x1f680;迭代实现 &#x1f680;前言 大家好啊&#xff01;阿辉接着更新排序算法&#xff0c;今天要讲的是归并排序&#xff0c;这里阿辉将讲到归并排序的递归实现和迭代实现&#xff…

LLM之llm-viz:llm-viz(3D可视化GPT风格LLM)的简介、安装和使用方法、案例应用之详细攻略

LLM之llm-viz&#xff1a;llm-viz(3D可视化GPT风格LLM)的简介、安装和使用方法、案例应用之详细攻略 目录 llm-viz的简介 1、LLM可视化 2、CPU模拟&#xff08;WIP&#xff1b;尚未公开&#xff01;&#xff09; llm-viz的安装和使用方法 llm-viz的案例应用 1、三维可视化…

智慧文旅:未来旅游业的数字化转型

随着科技的快速发展&#xff0c;数字化转型已经成为各行各业的必然趋势。旅游业作为全球经济的重要组成部分&#xff0c;也正经历着前所未有的变革。智慧文旅作为数字化转型的重要领域&#xff0c;正逐渐改变着旅游业的传统模式&#xff0c;为游客带来更加便捷、个性化的旅游体…

使用signal中止阻塞的socket函数的应用实例

在 socket 编程中&#xff0c;有一些函数是阻塞的&#xff0c;为了使程序高效运行&#xff0c;有一些办法可以把这些阻塞函数变成非阻塞的&#xff0c;本文介绍一种使用定时器信号中断阻塞函数的方法&#xff0c;同时介绍了一些信号处理和定时器设置的编程方法&#xff0c;本文…

【IM】如何保证消息可用性(一)

目录 1. 基本概念1.1 长连接 和 短连接1.2 PUSH模式和PULL模式 2. 背景介绍2.1 理解端到端的思想 3. 方案选型3.1 技术挑战3.2 技术目标 1. 基本概念 在讲解消息可用性之前&#xff0c;需要理解几个通信领域的基本概念。 1.1 长连接 和 短连接 什么是长连接&#xff0c;短连接…