【问题标题】:How to deal with api that rate limits requests?如何处理速率限制请求的api?
【发布时间】:2018-08-07 10:14:24
【问题描述】:

对于小型应用,它们没有问题。

但对于有流量的应用,您可以轻松达到限制。

Http 协议是 req-res 驱动的。仅仅因为您的后端受到限制,您真的不能等待发送响应,直到速率限制允许您继续进行 api 调用。

你是做什么的?

我能想到几个场景:

等一下:虽然很糟糕,但有时很容易解决,因为您不需要做任何事情。

排队:这很多工作与仅进行 api 调用相反。这要求您首先将其存储在数据库中,然后让后台任务通过数据库并执行任务。用户还会被告知“正在处理”而不是“完成”

使用大量 api:非常 hacky...而且管理起来很麻烦。假设您使用的是亚马逊,现在您必须创建、验证、验证 10 个帐户。甚至不可能在您需要使用域名进行验证的地方进行验证。因为亚马逊会知道账户 abc 已经拥有它。

【问题讨论】:

  • 付费访问?
  • 通过支付你仍然有限制,他们只是更高

标签: node.js architecture api-design throttling


【解决方案1】:

速率限制可能给您带来问题的原因有两个。

  1. 慢性:(即持续的情况)。您正在达到费率限制,因为您的持续需求超过了您的限额。 在这种情况下,请考虑使用本地缓存,这样您就不会两次请求相同的内容。希望您使用的 API 具有可靠的“最后修改”日期,以便您可以检测缓存何时过时。使用这种方法,您的 API 调用将刷新您的缓存,然后您从缓存中处理请求。

如果这不起作用,您需要更高的速率限制

  1. 急性:您的应用程序会发出超过速率限制的突发调用,但平均而言,您的需求低于限制。所以你有一个短期的问题。我已经为此确定了一个蛮力解决方案(“先拍摄,稍后请求许可”)。我爆发直到达到速率限制,然后我使用重试逻辑,这很容易,因为我首选的工具是 python,它很容易支持这一点。返回的错误被捕获并接管重试处理。我想每个成熟的图书馆都会有这样的东西。

    https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html

默认的重试逻辑是在越来越大的时间步长中回退。 我认为这有饥饿的风险。也就是说,如果有多个客户端使用相同的 API,则它们与池共享相同的速率限制。在您第 n 次重试时,您的退避时间可能会过长,以至于退避时间较短的新客户正在窃取您的插槽……当您的退避时间较长时,速率限制已被较年轻的竞争对手消耗,因此您现在重试甚至更长,使问题变得更糟。解决方案是提供一种不那么幼稚的算法,这与您在计算机科学中所做的锁定问题相同(引入随机化是一个很大的改进)。

【讨论】:

    【解决方案2】:

    扩展您的排队选项:

    除非您可以在@Hammerbot 走过时设计出不存在这个速率限制的问题,否则我会采用队列的一些实现。该解决方案可以根据您面临的负载以及您正在处理的速率受限 API 的数量来扩展复杂性和稳健性。

    推荐

    您使用一些库来为您处理这个问题。 Node-rate-limiter 看起来很有希望。看来您仍然需要担心如何处理用户交互(让他们等待,写入 db/cache-service 并稍后通知他们)。

    “最简单的情况” - 不推荐

    您可以实现一个功能最低的队列并使用数据库或缓存来支持它。我以前做过,最初很好。请记住,您将遇到需要实现自己的重试逻辑,将不得不担心queue starvation **之类的事情。基本上,应该考虑滚动你自己的的警告。

    **(例如,您的呼叫由于某种原因不断失败,突然间,您的后台进程无休止地重试大量失败的队列工作元素,并且您的应用程序内存不足)。

    复杂案例:

    您有一堆 API 调用,它们都受到速率限制,并且这些调用都是大量进行的,这使您开始考虑将架构解耦,这样您的面向用户的应用就不必担心处理这种异步背景处理。

    高层架构:

    您的面向用户的服务器将不同类型的工作单元推送到不同的队列中。这些队列中的每一个对应于不同的速率限制处理(例如,每小时 10 个查询,每天 1000 个查询)。然后,您有一个“速率限制服务”,它充当从不同队列中消耗工作单元的大门。然后,当且仅当速率限制服务表示可以时,水平分布的工作人员才使用队列中的项目。然后可以将这些工作人员的结果写入数据库,然后您可以有一些后台进程来通知您的用户您必须执行的异步工作的结果。

    当然,在这种情况下,您正在涉足基础设施问题的整个世界。

    为了进一步阅读,您可以使用Lyft's rate-limiting service(我认为它实现了token bucket algorithm 来处理速率限制)。您可以将Amazon's simple queueing service 用于队列,将Amazon lambda 用作队列消费者。

    【讨论】:

    • 这就是我所害怕的,这不仅仅是几个额外的步骤,它是全新的宇宙——你所描述的几乎是微服务......这意味着管理它们,这意味着 Kubernetes+docker+事件系统..列表不断。哦,好吧。
    【解决方案3】:

    我认为这取决于您要调用哪个 API 以及针对什么数据。

    例如,Facebook 将其 API 调用限制为每个用户每小时 200 个请求。因此,如果您的应用程序增长了,并且您正确使用了他们的 OAuth 实现,那么您不应该在这里受到限制。

    现在,您需要什么数据?你真的需要打所有这些电话吗?您调用的信息是否有点可以存储在您的任何服务器上

    假设您需要在网站上显示 Instagram 供稿。因此,在每次访问者请求时,您都会访问 Instagram 以获取所需的图片。当您的应用程序增长时,您会达到 API 限制,因为您的访问者数量超过了 Instagram API 允许的数量。在这种情况下,您绝对应该每小时将数据存储在您的服务器上一次,并让您的用户访问您的数据库而不是 Instagram 的数据库。

    现在假设您需要针对每个用户的每个请求提供特定信息。是否可以让该用户处理其与 API 的连接?通过实现 API 的 OAuth 2 流程或通过询问用户他们的 API 信息(我认为不是很安全...)?

    最后,如果你真的不能改变你现在的工作方式,我看不到你在这里列出的任何其他选项。

    编辑:最后,正如@Eric Stein 在他的评论中所说,一些 API 允许您通过付费来提高您的 API 限制(很多 SaaS 都这样做),所以如果您的应用程序增长,您应该负担得起这些费用服务(它们为您带来价值,回报它们是公平的)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      • 1970-01-01
      • 2023-03-11
      相关资源
      最近更新 更多