五个必知的速率限制策略,以最大化流量流动

速率限制是一种策略,我们在工作中常常使用,它定义了系统在设定的时间框架内可以处理的最大请求数量。

速率限制定义了系统在指定时间段内可以处理的最大请求数量。

Image.png

速率限制是一种策略,我们在工作中常常使用,它定义了系统在设定的时间框架内可以处理的最大请求数量。

  • 防御策略:这不仅仅是关于控制流量,而且还关于保护系统免受像DDoS攻击和潜在滥用等威胁。此外,不受限制的请求有时会成为攻击者利用漏洞的入口。
  • 确保公平性:我可以确保系统为每个人都表现出色,确保每个用户都能公平分享系统的资源。
  • 分层访问:对于高级用户,可以有更高的请求限制,而对于免费用户,则有一个标准限制。

在选择算法时,我遇到了几种不同的方法。

选择合适的方法至关重要,它应该与您的系统的特定需求以及您试图解决的挑战相一致。

1. 令牌桶

在速率限制方面,有一种方法我经常使用,这是由于它的简单性,对于本示例,我将在用户级别进行设置。

“那么‘在用户级别’到底是什么意思呢?” 实质上,它表示速率限制是为每个单独的用户定制的,确保为他们定制了独特的限制。想象一下,每个用户都被分配一个容量为5个令牌的桶,每当用户发出请求时,就会消耗1个令牌。在10分钟的时间内,系统被设计为能够在每个桶中重新填充3个令牌。如果用户的桶是空的,他们将无法再发出更多的请求,直到添加了一些令牌。以下是根据我的配置的详细说明:

  • 桶限制:5个令牌。
  • 请求使用:1个令牌。
  • 重新填充速率:10分钟/3个令牌。

Image.png

(1) 优点

我观察到这种方法的一个关键优势是它相当节约资源。它在内存上占用较少的空间,不会对CPU造成太大的负担。

“您提到每10分钟进行一次重新填充。如果有1000万用户,这不是很占资源吗?” 与其为每个用户不断重新填充令牌,您可以采用一种“懒惰重新填充策略”。这意味着只有在用户实际提交请求时才会更新令牌计数。

此外,该方法相对较容易实施。

它旨在支持突发行为。在闲置期间,令牌会积累到其最大限制,使用户偶尔能够快速连续发出多个请求。

(2) 缺点

调整参数可能需要一些权衡,因此确定理想的桶大小、重新填充速率和请求使用可能需要一些试验。

尽管允许突发行为可能是有利的,但它也有其缺点。存在用户在短时间内发送大量请求的潜在风险。为了避免突发行为,我们可以应用“漏桶”策略以实现更一致的工作流。

2. 漏桶

而令牌桶会快速处理每个请求,漏桶采用了不同的方法。对于这种方法,每个请求都有一个固定的处理时间。

想象一下漏桶的运作方式,就像一个队列,如果队列达到其容量,任何进入的请求都会被拒绝。

Image.png

“但为什么要给它起名字‘漏桶’呢?这里哪里有漏洞呢?” 想象一下,桶底部有一个小孔,可以让水稳定滴出。如果您比桶内的水流得更快,会发生什么?确切地说,它会溢出,任何多余的水,就像我们的多余请求一样,都会被丢弃。

(1) 它是如何运作的?

我们从一个最多可以容纳10个单位的桶开始,每个请求需要1秒来处理。

  • 时间0秒:桶是空的。
  • 时间1秒:您向桶内倒入8个单位,现在它有了8个单位。
  • 时间2秒:1个单位泄漏出去,剩下7个单位。
  • 时间4秒:还有6个单位,我们尝试添加5个单位,但只有4个可以放下,导致1个溢出。现在桶满了,有10个单位。

(2) 优点

  • 实施简单,在许多方面,它甚至比令牌桶更简单。
  • 平滑突发行为,因此没有突发,客户可以急匆匆,但我们总是保持冷静。

(3) 缺点

  • 不适合处理突发情况,比如特殊活动或假期期间。
  • 太多被丢弃的请求可能会成为问题

“但如果一个读取请求只需要100毫秒,而我们的排水速度设置为1秒呢?” 请求仍然需要1秒处理。不过,可以调整设置:允许低于1秒的请求以其自然速度进行处理。然而,这样做可能会促使用户淹没系统,从而抵消了漏桶的优势,也许在这种情况下有更适合的方法。

“如果我们有一个较慢的请求,比如1秒,但桶的排水速率只有200毫秒呢?” 桶会继续释放该请求,但这可能是我们的排水速率设置得太低的一个指标,所以要小心。

3. 固定窗口计数器

移向基于时间的算法,让我们讨论一下固定窗口计数器。虽然听起来有所不同,但我们仍然可以使用我们熟悉的“桶”和“令牌”来解释这个概念。

每小时(这个时间很关键),客户端都会得到一个空的请求桶。每次他们发出请求时,一个令牌就会被放入这个桶中。一旦桶满了,就不允许再发出更多的请求。

(您可以想象客户端从带有令牌的桶开始,每次请求都会拿走一个令牌,没有令牌意味着不能再发出更多请求。)

1*EdG-thC8YV5khwiWGo-X-Q.png

“但这与令牌桶方法有什么不同呢?” 我理解您的困惑,这两种方法似乎都在随时间分配令牌。固定窗口计数器在小时结束时不考虑以前的令牌使用情况,计数器在每个窗口结束时重置为0,与以前的活动无关。相反,令牌桶方法根据剩余的令牌重新填充:previous_tokens += refill_rate(但始终在其最大容量内)。

(11) 它是如何运作的?

我们正在使用一个1分钟的窗口,并且我们的计数器的上限设置为10

  • 时间0秒:计数器为0,一个客户端发送了5个请求,将计数器提升到5。
  • 时间10秒:又来了3个请求,将计数器推到8。
  • 时间30秒:另外2个请求,我们的计数器达到了10,这就是这个窗口的限制。
  • 时间40秒:一个客户端尝试另一个请求,但被拒绝了,限制已经达到。
  • 时间60秒:一个新的窗口开始了,我们的计数器重置为0。

(2) 优点

  • 这种方法易于实施和监控。
  • 一旦时间窗口重新开始,客户端可以立刻发送一整组请求,允许突发行为。

(3) 缺点

  • 存在一种突发请求在窗口边界的机会。
  • 用户必须等待重置才能发出请求

例如,对于一个1小时的窗口和一个10个请求的限制,客户端可以在7:59:59和8:00:00之间的过渡时刻发送20个请求

4. 滑动日志

将滑动日志视为固定窗口的更好版本。它旨在处理窗口边缘的请求太多的问题。

与其坚持刚性的窗口,这个方法随着时间的推移而滑动。

对于每个传入的请求,我们的系统将迅速记下其时间戳。每个新的请求都会引发快速的回顾,以查看“过去N秒内有多少请求。

1*rGCamyRYi0ovqjvSozC0yQ.png

(1) 它是如何运作的?

想象一下,我们将时间窗口设置为10秒,并将其限制为3个请求,这意味着在任何给定的10

秒内只允许3个请求。

  • 时间0秒:一个请求进来,我们做个标记 - [0]。
  • 时间4秒、8秒:又来了两个请求 - [0, 4, 8]。
  • 时间9秒:另一个请求尝试进来,但被拒绝,因为我们已经达到了限制。
  • 时间11秒:首先,我们去掉了超过10秒的旧条目,留下了[4, 8]。由于还有空间,这个请求被允许 - [4, 8, 11]。
  • 时间15秒:两个请求到达后,删除过时的条目后,我们的列表看起来像[8, 11]。但我们只能接受其中的一个,更新日志为 - [8, 11, 15]。

这个过程很清楚:删除旧日志,检查新请求,更新日志。

(2) 优点

  • 有助于避免在窗口边缘太多的请求
  • 客户端不需要等待完全重置,提供更均匀的请求流。

(3) 缺点

  • 它需要更多的计算能力,因为我们必须为每个新请求清理旧条目。
  • 由于需要跟踪时间戳,所以存储需求更大,如果我们的规模很大,这可能会成为一个问题。
5. 滑动窗口

对于滑动窗口,与滑动日志不同,我们略微简化了事情。我们关注的是最后一个窗口中的请求数量。

所以,如果你发现自己处于当前窗口的75%,你会权衡请求。25%来自上一个窗口,其余来自当前窗口:

权重 = (100 - 75)% * 上一个窗口的请求 + 当前窗口的请求

现在,当一个新请求试图加入这个过程时,你将这个权重加1(权重+1)。如果这个新的总数超过了我们设定的限制,我们必须拒绝这个请求。

1*js-77Ra-5xS-VVcVFlhdpw.png

它是如何运作的?

假设有一个每分钟10个请求的窗口。

让我们将这个过程分为两个阶段,窗口A为第一分钟,窗口B为第二分钟。

  • 在0秒:我们收到一个初始请求,这意味着窗口A的计数器开始计时,现在为A_counter = 1。
  • 在59秒:又来了7个请求,所以A_counter = 8。
  • 在1分6秒:一个客户端决定发送另外3个请求。记住我们从窗口A的计数器中得到的8?因为我们已经进入窗口B,大约有10%消失,我们将使用90%的窗口A计数器值进行下一次计算。

current_weight = 90% * A_counter + 0 = 7.2

这允许大约再添加2个请求(因为7.2 + 2 < 10)。但第三个请求呢?

很遗憾,它被拒绝了,B_counter现在为2。

“但如果一个客户在59秒时发送8个突发请求,然后在1分钟6秒时偷偷再发送2个,他们仍然能够通过,对吗?” 正是如此,这就是与滑动日志相比的一个小权衡。我们选择更少的计算工作和存储空间来换取更高的准确性。使用方程式(1 - 百分比通过)* 上一个窗口 + 当前窗口,我们猜测上一个窗口的请求在时间上是均匀分布的,而不是一次性全部到来。这是一个战略性的选择,旨在寻求一种更高效的方法,即使这意味着在准确性上有所减少。考虑到您的资源、如何管理突发流量、准确性以及您愿意处理多少复杂性,选择适合您需求的正确速率限制器。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

我终于体会到了:代码竟然不可以运行,为什么呢?代码竟然可以运行,为什么呢?

废话不多说&#xff0c;直接上图 初看只当是段子&#xff0c;再看已是段中人 事情经过&#xff1a; 我在写动态顺序表的尾插函数时&#xff0c;写出了如下代码&#xff0c;可以跑&#xff0c;但是这段代码有一个bug暂时先不提 //动态顺序表的尾插 void SLPushBack(SL* psl, …

【C++历练之路】list的重要接口||底层逻辑的三个封装以及模拟实现

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 在C的世界中&#xff0c;有一种数据结构&#xff0c;它不仅像一个神奇的瑰宝匣&#xff0c;还像一位能够在数据的海洋中航行的智慧舵手。这就是C中的list&#xff0c;一个引人入胜的工具…

数据结构【DS】树的性质

度为m的树 m叉树 至少有一个节点的度m 允许所有节点的度都<m 一定是非空树&#xff0c;至少有m1个节点 可以是空树 节点数 总度数 1m叉树&#xff1a; 高度为h的m叉树 节点数最少为&#xff1a;h具有n个结点的m叉树 最大高度&#xff1a;n度为m的树&#xff1a; 具有…

shell脚本学习笔记07

如何让shell实现 可选择性执行 的功能 用了while进行循环&#xff0c;是死循环&#xff0c;在循环时&#xff0c;使用case进行使用哪个脚本进行执行。使用clear进行每一次操作前的清屏&#xff0c;eof代表输入这个会显示目录。read用来读取输入的值&#xff0c;如果不输入值不会…

ScalableMap

问题引入 传统方案在处理线性地图元素时忽略了其结构性约束&#xff0c;建图距离太近 方法 简介 结构引导BEV特征提取 一种新的层次稀疏地图表示方法 设计渐进解码机制和基于此表示的监督策略 组件 结构引导BEV表征 通过车载摄像头捕捉的环绕视图图像&#xff0c;利用Res…

保险保险保险保险保险QAQ

该买保险啦&#xff01; 一、百万医疗险&#xff1a;事后报销医疗费用1、蓝医保 太平洋保险2、长相安 平安健康3、金医保 人寿保险4、好医保 人保健康 二、重疾险&#xff1a;确诊后一次性给付1、达尔文7号 国联人寿保险公司2、超级玛丽9号 君龙人寿3、守卫者6号 国联人寿保险公…

​软考-高级-系统架构设计师教程(清华第2版)【第7章 系统架构设计基础知识(263~285)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第7章 系统架构设计基础知识&#xff08;263~285&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

全链路监控--pinpoint

一、pinpoint架构原理 架构组成 Pinpoint Agent:和自己运行的应用关联起来的探针 Pinpoint Collector:收集各种性能数据 Pinpoint-Web: 将收集到的数据显成为 WEB网页显示 HBase Storage: 存储收集到的数据 工作原理 pinpoint的核心思想是在各个服务节点之间彼此调用时&a…

预定义宏指令

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h>int main() {printf("%s\n", __FILE__);printf("%d\n", __LINE__);printf("%s\n", __DATE__);printf("%s\n", __TIME__);return 0; } 运行结果&#xff1a;

记录将excel表无变形的弄进word里面来

之前关于这个问题记录过一篇文章&#xff1a; 将excel中的表快速复制粘贴进word中且不变形-CSDN博客 今天记录另外一种方法&#xff1a;举例表述&#xff0c;excel表如图&#xff1a; 按F12&#xff0c;出现“另存为...”对话框&#xff0c;选择“单个文件网页”&#xff0c;…

Java(二)(String的常见方法,ArrayList的常见方法)

String 创建string对象 package Helloworld;public class dome1 {public static void main(String[] args) {// 1.直接双引号得到字符串对象,封装字符串对象String name "lihao";System.out.println(name);// 2. new String 创建字符串对象,并调用构造器初始化字符…

汇编-指针

一个变量如果包含的是另一个变量的地址&#xff0c; 则该变量就称为指针(pointer) 。指针是操作数组和数据结构的极好工具&#xff0c;因为它包含的地址在运行时是可以修改的。 .data arrayB byte 10h, 20h, 30h, 40h ptrB dword arrayB ptrB1 dword OFFSET arrayBarray…

Linux中系统时间同步

在Windwos中&#xff0c;系统时间的设置很简单&#xff0c;界面操作&#xff0c;通俗易懂&#xff0c;而且设置后&#xff0c;重启&#xff0c;关机都没关系。系统时间会自动保存在BIOS时钟里面&#xff0c;启动计算机的时候&#xff0c;系统会自动在BIOS里面取硬件时间&#x…

庖丁解牛:NIO核心概念与机制详解 02 _ 缓冲区的细节实现

文章目录 PreOverview状态变量概述Position 访问方法 Pre 庖丁解牛&#xff1a;NIO核心概念与机制详解 01 接下来我们来看下缓冲区内部细节 Overview 接下来将介绍 NIO 中两个重要的缓冲区组件&#xff1a;状态变量和访问方法 (accessor) 状态变量是"内部统计机制&quo…

「Verilog学习笔记」根据状态转移表实现时序电路

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 可得逻辑表达式为 可得逻辑表达式为 timescale 1ns/1nsmodule seq_circuit(input A ,input clk ,input rst_n,outpu…

小美的排列构造

美团2024届秋招笔试第一场编程真题 贪心问题&#xff0c;得到所有n全排列中相邻两数的和&#xff0c;这些和差距要尽可能小。 显然如果1和2排一起&#xff0c;或者让n和n-1相邻都是错误的。最好的方式是让相邻两数的和接近&#xff08;n1&#xff09;/2。 比如:n 1 n-1 2...…

分组表,分桶表

1&#xff0c;启动Hive服务 &#xff08;1&#xff09;启动HiveServer2服务 nohup hive --service metastore &&#xff08;2&#xff09;启动Metastore服务 nohup hive --service hiveserver2 &&#xff08;3&#xff09;查看进程信息 lsof -i:100002&#xff0c;…

生物信息基础:实用Git命令,掌握这些就够了

我发现有搞了几年生信的朋友还不会用Github管理代码&#xff0c;这不免令人意外。我一直强调基础知识的重要性&#xff0c;而这些知识又是可以在短时间内掌握的。Github管理平时写的代码&#xff0c;要用到Git命令。虽然官方Git命令非常多&#xff0c;但我们只要掌握常用的几个…

初始ProtoBuf

目录​​​​​​​ ⼀、初识ProtoBuf 1. 序列化概念 2. ProtoBuf是什么 3. ProtoBuf的使用特点 ⼆、安装ProtoBuf 1、ProtoBuf在window下的安装 2、ProtoBuf在Linux下的安装 ⼀、初识ProtoBuf 1. 序列化概念 序列化和反序列化 序列化&#xff1a;把对象转换为字节序列…

037、目标检测-SSD实现

之——简单实现 目录 之——简单实现 杂谈 正文 1.类别预测层 2.边界框预测 3.多尺度输出联结做预测&#xff08;提高预测效率&#xff09; 4.多尺度实现 5.基本网络块 6.完整模型 杂谈 原理查看&#xff1a;037、目标检测-算法速览-CSDN博客 正文 1.类别预测层 类别…