Redis实现多种限流算法

news2024/12/28 20:29:03

一 常见限流算法

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) then
        allowed = 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
else
    return 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 then
    capacity = tonumber(ARGV[1])
    passRate = tonumber(ARGV[2])
    --请求一次所要加的水量,一定不能大于容量值的
    addWater=tonumber(ARGV[3])
    --当前储水量,初始水位一般为0
    water = addWater
    lastTs = tonumber(ARGV[4])
    redis.call('hmset', KEYS[1], 'capacity', capacity, 'passRate', passRate,'addWater',addWater,'water', water, 'lastTs', lastTs)
    return 1
else
    local 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 1
    end
    -- 请求失败
    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 then
        local tokens = math.min(current_tokens + new_tokens, capacity)
        redis.call('set', key, tokens)
        redis.call('set', key .. ':last_refreshed', now)
    end

    if current_tokens < reqTokens then
        redis.call('decr', key)
        return 1
    else
        return 0
    end
end

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

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

相关文章

PBM模型学习(五)UDF生长模型

DEFINE_PB_GROWTH_RATE(name, cell, thread, d_i) 该UDF在每个时间步开始时执行,只有在时间步开始时,颗粒粒径才会更新,同时才会UDF才会向文件写入数据GR单位是m/sC_PHASE DIAMETER(c,ts):返回颗粒粒径???,ts为颗粒相的线程C_VOF(cell,thread):颗粒相总体积C_PB DISCI(c…

在DevEco开发工具中,使用Previewer预览界面中的UI组件

1、在DevEco工具中&#xff0c;点击并展开PreViewer预览器 2、在PreViewer预览器中&#xff0c;点击Tt按钮&#xff08;Inspector&#xff09;切换至组件查看模式 3、在组件查看模式下选择组件&#xff0c;代码呈现选中状态&#xff0c;右侧呈现组件树&#xff0c;右下方呈现组…

FLStudio21.2.2国内中文版本怎么下载?

FL studio简称FL&#xff0c;全称&#xff1a;Fruity Loops Studio。在中国我们习惯叫它"水果"。它让你的计算机就像是全功能的音乐工作站&#xff0c;大混音盘&#xff0c;非常先进的制作工具&#xff0c;让你的音乐突破想象力的限制。 FL Studio主要功能 1、FL St…

Authorization Failed You can close this page and return to the IDE

一.问题描述 注册JetBrains成功&#xff0c;并且通过了学生认证&#xff0c;但在activate pycharm时&#xff0c;却显示Authorization Failed You can close this page and return to the IDE如上图 二.原因&#xff1a; 可能是因为之前使用了破解版pycharm 三.解决方法&am…

2024阿里云和腾讯云的第一战打响:搭建《幻兽帕鲁》私服游戏

为了搭建《幻兽帕鲁》游戏私服&#xff0c; 2024年阿里云 VS 腾讯云的第一场战争开始了…… 事情是这样的&#xff1a; 1月19日&#xff0c;最离谱新游 《幻兽帕鲁》突然爆火了&#xff0c;这是一款日本开发商展耗费4年开发的冒险类游戏&#xff0c;这款戏一推出就迅速俘获了…

KT6368A蓝牙芯片开发app小程序接口api里面的device ID是什么?

KT6368A蓝牙芯片开发app或者小程序的时候&#xff0c;给出的接口api&#xff0c;里面的device ID是什么&#xff1f; 有客户在开发app的过程中&#xff0c;问到我们device ID的问题 其实这个问题您稍微有点方法&#xff0c;直接百度搜搜就很清楚了&#xff0c;但是没办法&…

Linux 网络流量相关工具

本文聚焦于网络流量的查看、端口占用查看。至于网络设备的管理和配置&#xff0c;因为太过复杂且不同发行版有较大差异&#xff0c;这里就不赘述&#xff0c;后面看情况再写。 需要注意的是&#xff0c;这里列出的每一个工具都有丰富的功能&#xff0c;流量/端口信息查看只是其…

uniCloud发行部署H5进行网页托管

生成文件&#xff0c;生成文件这个和我们平时用uniapp 生成H5的时候是一样的&#xff0c;我们可以选择hash 或者history 模式&#xff0c;默认的这是显示的根目录&#xff0c;如果我们在根目录下建立了H5目录&#xff0c;那么我们在发布H5的时候&#xff0c;是需要在manifest.j…

vue3 codemirror关于 sql 和 json格式化的使用以及深入了解codemirror 使用json格式化提示错误的关键代码

文章目录 需求说明0、安装1. 导入js脚本2.配置3.html处使用4.js处理数据&#xff08;1&#xff09;json格式化处理&#xff08;2&#xff09;sql格式化处理 5. 解决问题1:json格式化错误提示报错&#xff08;1&#xff09;打开官网&#xff08;2&#xff09;打开官网&#xff0…

【css揭秘】

文章目录 背景与边框半透明边框多重边框box-shadowoutline 背景定位background-positionbackground-origincalc() 条纹背景水平条纹 形状圆形圆柱自适应的椭圆半椭圆四分之一椭圆 背景与边框 半透明边框 目标&#xff1a;给一个容器设置一层白色背景和一道半透明白色边框 写…

机器学习_集成学习之Bagging(集成多个模型,以降低整体的方差)

文章目录 Bagging 算法 —— 多个基模型的聚合决策树的聚合从树的聚合到随机森林从随机森林到极端随机森林 Bagging 算法 —— 多个基模型的聚合 Bagging 是我们要讲的第一种集成学习算法&#xff0c;是Bootstrap Aggregating 的缩写。有人把它翻译为套袋法、装袋法&#xff0…

Flutter App 生命周期观察监听

前言 本文主要讲解两种 Flutter生命周期观察监听 方式一&#xff1a;Flutter SDK 3.13 之前的方式&#xff0c;WidgetsBindingObserver&#xff1b; 方式二&#xff1a;Flutter SDK 3.13 开始的新方式&#xff0c;AppLifecycleListener&#xff1b; 测试平台&#xff1a;IO…

HCS 华为云Stack产品组件

HCS 华为云Stack产品组件 Cloud Provisioning Service(CPS) 负责laas的云平台层的部署和升级是laas层中真正面向硬件设备&#xff0c;并将其池化软件化的部件。 Service OM 资源池(计算/存储/网络)以及基础云服务(ECS/EVS/PC)的管理工具。 ManageOne ManageOne包括服务中心…

IMX6ULL驱动学习——通过总线设备驱动模型点亮野火开发板小灯【参考韦东山老师教程】

参考&#xff1a;【IMX6ULL驱动开发学习】11.驱动设计之面向对象_分层思想&#xff08;学习设备树过渡部分&#xff09;-CSDN博客 韦东山课程&#xff1a;LED模板驱动程序的改造_总线设备驱动模型 我使用的开发板&#xff1a;野火imx6ull pro 欢迎大家一起讨论学习 实现了总线设…

大型语言模型基础知识的可视化指南

直观分解复杂人工智能概念的工具和文章汇总 如今&#xff0c;LLM&#xff08;大型语言模型的缩写&#xff09;在全世界都很流行。没有一天不在宣布新的语言模型&#xff0c;这加剧了人们对错过人工智能领域的恐惧。然而&#xff0c;许多人仍在为 LLM 的基本概念而苦苦挣扎&…

c++学习第十三讲---STL常用容器---string容器

string容器&#xff1a; 一、string的本质&#xff1a; string和char*的区别&#xff1a; char*是一个指针 string是一个类&#xff0c;封装了char*&#xff0c;管理这个字符串&#xff0c;是char*的容器。 二、string构造函数&#xff1a; string() ; …

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Swiper容器组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Swiper容器组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Swiper容器组件 滑块视图容器&#xff0c;提供子组件滑动轮播显示的能力。…

独享http代理安全性是更高的吗?

不同于共享代理&#xff0c;独享代理IP为单一用户提供专用的IP&#xff0c;带来了一系列需要考虑的问题。今天我们就一起来看看独享代理IP的优势&#xff0c;到底在哪里。 我们得先来看看什么是代理IP。简单来说&#xff0c;代理服务器充当客户机和互联网之间的中间人。当你使用…

CIFAR-10数据集详析:使用卷积神经网络训练图像分类模型

1.数据集介绍 CIFAR-10 数据集由 10 个类的 60000 张 32x32 彩色图像组成&#xff0c;每类 6000 张图像。有 50000 张训练图像和 10000 张测试图像。 数据集分为5个训练批次和1个测试批次&#xff0c;每个批次有10000张图像。测试批次正好包含从每个类中随机选择的 1000 张图像…

GitHub 一周热点汇总第7期(2024/01/21-01/27)

GitHub一周热点汇总第7期 (2024/01/21-01/27) &#xff0c;梳理每周热门的GitHub项目&#xff0c;离春节越来越近了&#xff0c;不知道大家都买好回家的票没有&#xff0c;希望大家都能顺利买到票&#xff0c;一起来看看这周的项目吧。 #1 rustdesk 项目名称&#xff1a;rust…