【问题标题】:How to manage request limited API calls如何管理请求受限的 API 调用
【发布时间】:2012-11-05 17:30:33
【问题描述】:

我正在使用 tmdb API,它对请求有一个新的限制,即每个 IP 在 10 秒内 30 个请求。我可以通过在 MySQL 中创建一个包含过去 10 秒请求数量的表来跟踪这些调用,但是如何使用不同的 IP 地址来实现呢?

我的应用程序的工作方式是:

  1. 从桌面应用程序向应用程序服务器发出请求。服务器端php然后进行搜索并返回数据。

  2. 然后桌面应用程序对应用程序服务器进行不同的调用,然后依次对 tmdb (4-7) 和其他 api 进行多次 api 调用。

在某些情况下,可能有几个搜索请求,也可能有几千个。跟踪和延迟 api 调用以使其低于限制的最佳方法是什么?

【问题讨论】:

    标签: php mysql sql api rate-limiting


    【解决方案1】:

    如果您的服务器正在向具有速率限制的另一台服务器发送请求,您将需要一种全局方式来跟踪来自您服务器的请求,而不管哪个客户端正在向您的服务器发出请求等。

    我会使用一个平面文件,并为每个请求节省 unix 时间和一个分隔符,如果文件包含其中的十个,那么你已经完成了十个请求,你需要清理文件并删除任何时间戳超过 10 秒,这将为您提供最简单的 PHP 速率限制器形式。

    当然还有更高级的方法,但我会从那里开始,并确保您对其进行测试,以免失去您的 API 访问权限等。

    【讨论】:

    • 在我看来,使用 MySQL 进行跟踪更简单(因为我已经大量使用 MySQL)。您是否知道每 30 秒重置一次 MySQL 字段的方法,例如在没有 php 的情况下(有点像自动增量,除了相反和时间相关)?这会将我的查询简化为每个 API 调用的简单增量。
    • 我猜你误会了一件事。您必须注意的请求数量仅适用于您的应用服务器。无论有 100 个或 1000 个桌面客户端访问您的应用服务器,这都无关紧要。它是关于您的应用服务器访问 tmdb 的请求数。所以简而言之,只有 1 个 IP 必须对您的应用服务器进行速率限制。
    • 如果将来如果您想从桌面客户端拨打电话,那么在您的客户端代码中,您还必须对独立的桌面 IP 进行速率限制,假设不超过单个桌面客户端共享相同的 IP .
    • 您将像清理文件一样清理数据库,对于每个请求,您都必须获取时间戳并删除超过特定时间的时间戳。您不能每 30 秒就将它们全部删除,因为那样会不一样。这不仅仅是数到十,然后等待几秒钟等的问题。您需要知道每个请求何时发出,以确保每 10 秒 10 次或任何限制都没有达到。
    • 你当然可以使用 MySQL,但我很确定,对于几个字节的数据,一个平面文件会快很多,而且对于许多请求,速度和简单性就是一切。您也可以使用基于内存的存储,这样会更好。
    【解决方案2】:

    您可以使用 php sleep 功能来限制您发出请求的速率。或者确实使用类似 usleep 功能的东西,通过提供您想要延迟的微秒数来暂停。

    【讨论】:

    • 是的,但我如何在请求之间跟踪这一点? (例如,在对 php 文件的调用之间)php 是否也没有超时(它可能从 7 个请求开始,并且之前有大量请求)?
    • 您可以维护一个日志(可能通过维护一个 sql 表),以了解您在时间跨度内发出了多少请求,并通过使用 sleep 方法停止相应的速率限制。
    • 好的,但是当我只需要限制每个唯一的 IP 地址时,它会限制所有用户请求。
    • 如果使用 PHP 进行请求,IP 地址将是您的服务器,而不是用户。
    • 您提到您的桌面应用程序正在向应用程序服务器发出请求,该请求又会访问 tmdb 服务器。所以在真正意义上,唯一需要速率限制的 IP 将是您的应用服务器的 IP。它与您的桌面客户端无关。告诉我您的查询是否正确。
    【解决方案3】:

    token bucket algorithm 可以做速率限制。我为你做了一个带有共享存储的线程安全实现:bandwidth-throttle/token-bucket

    此示例将应用程序限制为每秒 3 个请求的全局消耗率:

    use bandwidthThrottle\tokenBucket\Rate;
    use bandwidthThrottle\tokenBucket\TokenBucket;
    use bandwidthThrottle\tokenBucket\BlockingConsumer;
    use bandwidthThrottle\tokenBucket\storage\PDOStorage;
    
    $storage  = new PDOStorate("tmdb", $pdo);
    $rate     = new Rate(3, Rate::SECOND);
    $bucket   = new TokenBucket(30, $rate, $storage);
    $consumer = new BlockingConsumer($bucket);
    $bucket->bootstrap(30);
    
    $consumer->consume(1);
    $api->foo();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-14
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      • 2018-08-07
      • 2019-01-03
      相关资源
      最近更新 更多