如何在Python中限制对Web服务的请求率?

时间:2008-12-30 19:30:11

标签: python web-services rate-limiting

我正在开发一个与Web服务API接口的Python库。像我遇到的许多Web服务一样,这个服务请求限制请求的速率。我想向类实例化提供一个可选参数limit,如果提供的话,它将保存传出请求,直到指定的秒数通过。

我理解一般情况如下:该类的实例通过方法发出请求。当它发生时,该方法发出一些信号,在某处设置一个锁定变量,并在limit中开始一个倒数计时器的秒数。 (很可能,锁定是倒数计时器本身。)如果在此时间范围内发出另一个请求,它必须排队,直到倒数计时器达到零并且锁定被解除;此时,队列中最早的请求被发送,倒计时器被重置并重新锁定。

这是线程的情况吗?我还没有看到另一种方法吗?

倒计时器和锁是否应该是实例变量,或者它们是否属于该类,以便该类的所有实例都保存请求?

另外,在库中提供速率限制功能通常是个坏主意吗?我的理由是,默认情况下,倒计时为零秒,库仍然允许开发人员使用库并提供他们自己的速率限制方案。鉴于任何使用该服务的开发人员都需要对请求进行速率限制,不过,我认为图书馆提供速率限制的方便是一种便利。

无论在库中是否设置了速率限制方案,我都希望使用该库编写应用程序,因此建议的技术将派上用场。

非常感谢您的建议!

克里斯

6 个答案:

答案 0 :(得分:7)

使用队列和调度程序可以更好地工作。

您将处理分为两个方面:来源发送。这些可以是单独的线程(如果更容易的话,可以是单独的进程)。

来源一边以任何速度创建和排队请求,让他们满意。

Dispatch 方面会这样做。

  1. 获取请求开始时间 s

  2. 将请求出列,通过远程服务处理请求。

  3. 获取当前时间 t 。睡眠为 - ( t - s )秒。

  4. 如果要运行直接连接到远程服务的端,可以执行此操作,并绕过速率限制。这对于使用模拟版本的远程服务进行内部测试非常有用。

    关于这一点的难点在于为每个可以入队的请求创建一些表示。由于Python Queue几乎可以处理任何事情,因此您无需执行任何操作。

    如果您正在使用多重处理,则必须pickle您的对象将它们放入管道中。

答案 1 :(得分:2)

排队可能过于复杂。一个更简单的解决方案是为您的类提供上次调用服务时的变量。每当调用服务(!1)时,将waitTime设置为delay - Now + lastcalltimedelay应该等于请求之间的最小允许时间。如果这个数字是正数,那么在打电话之前要睡一会儿(!2)。这种方法的缺点/优点是它将Web服务请求视为同步。优点是它非常简单且易于实现。

  • (!1):应该在收到服务的响应之后,在包装器内部(可能在包装器的底部)发生。
  • (!2):在包装器顶部调用Web服务的python包装器时应该发生。

当然,S.Lott的解决方案更优雅。

答案 2 :(得分:1)

您的速率限制方案应该受到底层代码(同步或异步)的调用约定的严重影响,以及此速率限制将在什么范围(线程,进程,机器,集群?)运行。

我建议保留实例中的所有变量,这样您就可以轻松实现多个句点/控制率。

最后,听起来你想成为一个中间件组件。不要试图成为一个应用程序并自己引入线程。如果你是同步的,只需阻塞/休眠,如果你被其中一个人调用,就使用异步调度框架。

答案 3 :(得分:1)

如果您的图书馆设计为同步,那么我建议省略限制执行(尽管您可以跟踪费率并至少帮助来电者决定如何遵守限制)。

我现在使用twisted与几乎所有内容进行交互。通过使用将请求提交与响应处理分开的模型,可以轻松地执行此类操作。如果您不希望您的API用户必须使用twisted,那么您至少应该更好地理解他们的API以进行延迟执行。

例如,我有一个Twitter界面,代表xmpp users推送了相当荒谬的请求数量。我没有率限制,但我确实需要做一些工作来防止所有请求同时发生。

答案 4 :(得分:1)

除非需要,否则不要重新发明轮子。检查真棒库ratelimit。如果你只是想以任何理由限制你的休息时间来限制你的生活,那就完美了。

答案 5 :(得分:0)

所以我假设一些简单的事情 进口时间 time.sleep(2) 在请求之间等待2秒不起作用