实现速率限制的初学者指南

如果你之前接触过后端服务,你可能听说过速率限制(Rate Limit)这个术语。

如果没有这个关键的工具包,客户端可以在任何时间点向你的服务发起无限多的请求。这会导致突然的流量激增,从而使你的服务器负载过重。

在这篇博文中,让我们回归基础,讨论四种常用的速率限制算法。

令牌桶(Token Bucket)

在其他四种算法中,令牌桶是最容易实现的之一。

让我们看看简化后的步骤。

1*3lp4BzvAg4KfG3Q7k4WUig.png

?想象一下有一个包含 N 个令牌的桶?如果有一个请求到达,我们从桶中取出一个令牌并处理该请求?假设没有剩余的令牌,我们将丢弃该请求而不进行处理。?在每个固定的时间间隔内,我们将桶中的令牌重新补充到 N 个。

我们可以使用一个简单的哈希映射来实现这个算法。

假设每个用户每分钟只能触发四个请求。

用户ID = 123

usersBucket[userID] = 4

当收到一个请求时,我们将usersBucket[userID]中的计数器减去1。如果令牌用完了,我们就丢弃该请求。每分钟,我们将哈希映射中的计数器重置为4

这里有一个棘手的情况:

实现速率限制的初学者指南
1*eaLShCqFe9TjVvL48GiktA.png

?12:00:59:用户触发了四个请求?12:01:00:我们将令牌重置为 4?12:01:01:用户再次触发了四个请求

在上面的情况中,用户在三秒内触发了八个请求!

为了确保流量更加平稳,令牌的补充速率应该与速率限制不同。

假设我们的速率限制是每分钟四个请求。我们可以每15秒添加一个令牌,而不是每分钟添加四个令牌。这样可以防止在重置边界处突然爆发的流量。

漏桶(Leaky Bucket)

在前面的算法中,虽然我们每15秒补充一次令牌,但用户仍然可以在第14秒触发四个请求,从而导致流量突然激增。

漏桶在确保流量更平稳分布方面非常有用。

以下是简化后的步骤:

实现速率限制的初学者指南
1*PqKJnOsvSvq8N9jrAG9gEg.png

?想象一下桶底部有一个孔的桶?当一个请求到达时,我们将请求放入桶中?在每个固定的时间间隔内,一个请求从底部“漏出”并得到处理

漏桶遵循先进先出(FIFO)的概念。我们可以使用队列来实现它。

每个到达的请求不会被丢弃,而是被入队到一个桶中。在每个固定的时间间隔内,第一个到达的请求将被出队并处理。

使用漏桶,请求可以以不同的速率到达,而服务器以恒定且可预测的速率进行处理。

正如俗话说,“没有最好的解决方案,只有权衡。” 一个恒定的速率意味着漏桶以平均速率处理请求,从而导致响应时间较慢。

固定窗口(Fixed Window)

固定窗口与令牌桶类似,两者都可能遭受突然的流量激增。

同样,让我们简化步骤。假设我们要实现每分钟四个请求的速率限制:

实现速率限制的初学者指南
1*BJ4At3xkfd_Xt8L8OVXvNQ.png

?时间线根据每个窗口的分钟数进行划分?每个窗口包含一个计数器为 4?当一个请求到达时,我们根据时间戳的下取整来分配请求?如果请求在 12:01:45 到达,则分配到 12:01:00 窗口?如果计数器大于 0,我们减少计数器并处理请求?否则,我们丢弃请求

1*CFGddTZBGG3HnOn2aoI48g.png

当所有请求在窗口边界处同时到达时,会发生流量激增

固定窗口算法最大的缺点是:

?它有可能在窗口边界附近导致突然的流量激增?如果计数器在窗口开始时用完,所有客户端都需要等待较长的重置窗口

滑动窗口(Sliding Window)

滑动窗口算法与固定窗口算法非常相似,只是它解决了上述缺点。

假设我们要实现每分钟四个请求的速率限制:

1*GUMxe0SwVA8TlEEs2BTDig.png

请求 5 将被处理并添加到数组中,因为在过去 1 分钟内只有 3 个请求被处理。请求 1 将被弹出。

?使用一个数组,也就是窗口,来存储已处理的请求,以及它们的时间戳?当一个请求到达时,我们遍历数组并检查在过去一分钟内处理的请求数?如果在过去一分钟内处理的请求数少于四个,我们将请求添加到数组中并处理它?随着我们遍历数组,我们弹出在一分钟前长时间处理的请求

正如你所看到的,滑动窗口算法是确保在任何给定时间点严格遵守速率限制的理想选择。

由于我们将过去 1 分钟的所有请求存储在内存中并在每次到达请求时遍历数组,所以该算法消耗更多的内存和CPU。

结论

每种算法都具有不同的优点和限制。

因此,在决定应用程序所承受的权衡时,了解它们的工作原理变得至关重要。

原创文章,作者:小技术君,如若转载,请注明出处:https://www.sudun.com/ask/33918.html

(0)
小技术君的头像小技术君
上一篇 2024年4月19日
下一篇 2024年4月19日

相关推荐

  • 为什么不要用stop方法停止线程?

    线程启动完毕后,在运行时可能需要终止,Java提供的终止方法只有一个stop,但是我不建议使用这个方法,因为它有以下三个问题:(1)stop方法是过时的从Java编码规则来说,已经…

    CDN资讯 2024年4月3日
    0
  • Spring5-Reactor函数式编程

    前言 反应式编程是一种可以替代命令式编程的编程范式。这种可替代性存在的原因在于反应式编程解决了命令式编程中的一些限制。理解这些限制,有助于你更好地理解反应式编程模型的优点 反应式流…

    2024年4月10日
    0
  • 国内cdn服务商排名,cdn服务器有哪些

    《国内CDN服务商排名:寻找最佳解决方案》 在当今数字化时代,网站性能对于在线业务的成功至关重要。随着网络用户数量的不断增长,确保网站内容快速加载成为吸引和保留用户的关键。为了应对…

    2024年5月11日
    0
  • 怎么去选消息队列? Kafka vs. RabbitMQ

    在上周,我们讨论了使用消息队列的好处。然后我们回顾了消息队列产品的发展历史。如今,在项目中需要使用消息队列时,Apache Kafka似乎是首选产品。然而,考虑到特定需求时,它并不…

    2024年4月18日
    0

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注