用Java构建一个简单的速率限制器


从 Android 的角度用Java构建一个简单的速率限制器:

从 Android 的角度使用

  1. 考虑这样一种情况,您正在编写代码来捕获用户的签名。当他们拖动指针时,您捕获了数千个点。平滑签名可能不需要所有这些,因此您可以使用速率限制进行采样。
  2. 某些事件调用频率很高。你可以控制它。
  3. 我们有MessageQueue空闲的监听器。当我们在主线程中监听它时,它会以一种随意的方式被调用。有时,它会在一秒钟内被调用几次。如果我们想构建一个心跳系统来告诉我们主线程何时空闲,我们可以使用它来接收每秒的事件。如果我们一秒钟都没有收到事件,我们可以假设主线程很忙。
  4. 对于框架/库的 API 配额管理,您可以根据用户选择的付款计划来控制 API 调用。

为了建立我们的速率限制器的核心,我们需要确保在任何两秒之间,我们不应该允许超过N个交易。我们将如何做到这一点?

考虑一下我们进行第一笔交易的时刻t0。所以。
直到(t0 + 1)s,我们只允许做N个交易。那么如何确保这一点呢?在进行下一次交易时,我们将检查是否
当前时间≤(t0+1)。如果不是,那就意味着我们已经进入了另一个秒,我们被允许进行N次交易。让我们看看一个小的代码部分来证明这一点。

long now = System.nanoTime();
if (now <= mNextSecondBoundary) { // If we are within the time limit of current second
    if (mCounter < N) {
// If token available
        mLastExecutionNanos = now;
        mCounter++;
// Allocate token
        invoke(code);
// Invoke the code passed the throttle method.
    }
}

详细点击标题见源码


速率限制
现实世界的用户是残酷的、不耐烦的和鬼鬼祟祟的。在高并发系统中,您的服务器可能会受到虚假请求的轰炸,因此您可能希望对其进行控制。
一些现实世界的用例可能如下:
1. API 配额管理——作为提供商,您可能希望根据用户采用的付款计划来限制向您的服务器发出 API 请求的速率。这可能在客户端或服务端。
2. 安全——防止 DDOS 攻击。
3. 成本控制——这不一定是针对服务端,甚至是客户端。如果某个组件以非常高的速率发出事件,它可以帮助控制它。它可以帮助控制从客户端发送的遥测数据。

我们在限速时的选择
根据我们正在处理的请求/事件的类型,可能会发生以下情况:

  1. 我们可以放弃额外的请求
  2. 我们可以选择让请求等待,直到系统将它们限制到预定义的速率。

常见的限速算法

  1. 令牌桶算法
  2. 漏桶算法
  3. 固定窗口

我们不会深入探讨这些算法的内部细节,因为它超出了本文的范围。
我们将以固定窗口算法为支点。让我们写下实施的高级要求。
固定窗口 ——窗口被预先分割,每个窗口都有一个计数器。每个请求都会将计数器加一。一旦计数器达到阈值,新请求将被丢弃,直到新的时间窗口开始。

要求

  1. 应该能够接受每秒或速率所需的 (TPS) 交易。
  2. 如果超过我们定义的速率,应该放弃交易。
  3. 应该在并发情况下工作。