【问题标题】:What's a good way to enforce a single rate limit on multiple machines?在多台机器上实施单一速率限制的好方法是什么?
【发布时间】:2014-05-07 03:40:51
【问题描述】:

我有一个带有负载平衡器的 Web 服务,可以将请求映射到多台机器。这些请求中的每一个最终都会向外部 API 发送一个 http 调用,因此我想限制我发送到外部 API 的请求数量。

我目前的设计:

  • 服务在内存中有一个队列,用于存储所有收到的请求
  • 我限制了我们从队列中获取请求并处理它的频率。

这在我使用多台机器时不起作用,因为每台机器都有自己的队列和速率限制器。例如:当我将我的速率限制器设置为 10,000 个请求/天,并且我使用 10 台机器时,我最终将在满负荷下处理 100,000 个请求/天,因为每台机器每天处理 10,000 个请求。我想限制速率,以便每天只处理 10,000 个请求,同时仍然对这 10,000 个请求进行负载平衡。

我正在使用 Java 和 MYSQL。

【问题讨论】:

  • 显而易见的解决方案是为 http api 创建一个公共队列或公共path。公共路径可能是一种代理,例如软件,它会限制每个基础的请求数量(在您的情况下是每天)。另外,你能在 API 端创建队列吗?

标签: java mysql concurrency throttling rate-limiting


【解决方案1】:
  1. 使用 memcached 或 redis 为每个客户端保留 api 请求计数器。检查每个请求是否超出速率限制。
  2. 如果你觉得对每个请求都进行检查过于昂贵,你可以尝试使用storm来处理请求日志,并异步计算请求计数器。

【讨论】:

    【解决方案2】:

    你说的两件事是:

    1)"I would like to rate limit so that only 10,000 requests get processed/day"
    2)"while still load balancing those 10,000 requests."
    

    首先,您似乎在使用分而治之的方法,最终用户的每个请求都映射到 n 台机器中的一台。因此,为了确保在给定的时间跨度内只处理 10,000 个请求,有两种选择:

    1) 实现一个组合器,它将所有 n 台机器的结果路由到
    然后外部 API 可以访问的另一个端点。该端点能够 记录正在处理的作业数量,如果超过您的阈值, 然后拒绝工作。

    2) 另一种方法是将您当天处理的工作量存储为变量 在你的数据库里面。然后,通常的做法是检查您的阈值是否 根据作业的初始请求,您的数据库中的值已达到 (在您甚至将其传递给您的一台机器之前)。如果阈值已经 达到,然后拒绝一开始的工作。这与适当的消息相结合,具有为最终用户提供更好体验的优势。

    为了确保所有这 10,000 个请求仍处于负载平衡状态,以便没有 1 个 CPU 处理的作业比任何其他 cpu 多,您应该使用简单的循环方法将作业分配到 m 个 CPU 上。与 bin/categorization 方法相反,使用循环法,您将确保作业请求尽可能均匀地分布在您的 n 个 CPU 上。循环法的一个缺点是,根据您正在处理的作业类型,您可能会在开始扩大规模时复制大量数据。如果这对您来说是一个问题,您应该考虑实现一种形式的局部敏感哈希 (LSH) 函数。虽然一个好的散列函数会尽可能均匀地分布数据,但如果您选择散列的属性中的偏差很可能发生,LSH 会使您发现 CPU 处理的作业比其他 CPU 多。与往常一样,两者都需要权衡取舍,因此您将最了解您的用例。

    【讨论】:

      【解决方案3】:

      为什么不在您的数据库中实现一个简单的计数器并让 API 客户端实现限制?

      用户代理 -> LB -> 你的服务 -> Q -> 你的 Q 消费者 -> API 客户端 -> 外部 API

      API 客户端检查数字(今天),您可以实现任何您喜欢的速率限制算法。例如,如果数字> 10k,客户端可能会简单地崩溃,让异常将消息放回队列并继续处理直到今天现在明天,所有排队的请求都可以得到处理。

      或者,您可以实施分层节流系统,例如直到 8k,然后每个节点每 5 秒发送 1 条消息,直到达到限制,此时您可以将 503 错误发送回用户代理。

      否则,您可以走复杂的路线并实现分布式队列(例如 AMQP 服务器),但这可能无法完全解决问题,因为您唯一的控制机制将是节流,因此您的处理速度永远不会比小于最大值的速度快每天限制。例如,您的最大限制是 10k,因此您的速度永远不会超过每 8 秒 1 条消息。

      【讨论】:

        【解决方案4】:

        如果您不反对使用库/服务,https://github.com/jdwyah/ratelimit-java 是一种获得分布式速率限制的简单方法。

        如果性能最受关注,您可以在一个请求中获取超过 1 个令牌,这样您就不需要向限制器发出 10 万次 API 请求。有关详细信息,请参阅https://www.ratelim.it/documentation/batches

        【讨论】:

          猜你喜欢
          • 2010-10-14
          • 2018-10-25
          • 2011-01-20
          • 1970-01-01
          • 1970-01-01
          • 2010-11-29
          • 2021-11-20
          • 1970-01-01
          相关资源
          最近更新 更多