use bandwidthThrottle\tokenBucket\Rate;
use bandwidthThrottle\tokenBucket\TokenBucket;
use bandwidthThrottle\tokenBucket\storage\FileStorage;
$storage = new FileStorage(__DIR__ . "/api.bucket");
$rate = new Rate(10, Rate::SECOND);
$bucket = new TokenBucket(10, $rate, $storage);
$bucket->bootstrap(10);
if (!$bucket->consume(1, $seconds)) {
http_response_code(429);
header(sprintf("Retry-After: %d", floor($seconds)));
exit();
}
8条答案
按热度按时间fruv7luv1#
好吧,没有办法在不向服务器写入任何数据的情况下完成我要求的任务,但我至少可以消除对每个请求的日志记录。一种方法是使用“漏桶”节流方法,其中它仅跟踪最后一个请求(
$last_api_request
)和时间帧的请求数量/限制的比率($minute_throttle
)。漏桶永远不会重置计数器(不像Twitter API的节流阀每小时重置一次),但是如果桶满了(用户达到了限制),他们必须等待n
秒,让桶空一点,然后才能发出另一个请求。换句话说,它就像一个滚动限制:如果在该时间帧内存在先前的请求,则它们正在缓慢地从桶中泄漏出来;它只会在你装满水桶的时候限制你。此代码片段将在每个请求上计算新的
$minute_throttle
值。我在$minute_throttle
中指定了 minute,因为您可以为任何时间段添加限制,例如每小时,每天等。尽管多于一个将很快开始使用户感到困惑。字符串
wecizke32#
您可以使用token bucket algorithm控制速率,这与漏桶算法相当。请注意,您必须共享存储桶的状态(即令牌的数量)。因此,您可能需要考虑使用锁定来避免竞态条件。
好消息是:我做的一切都是为了你:bandwidth-throttle/token-bucket的
字符串
tgabmvqs3#
最简单的解决方案是每24小时给予每个API密钥有限数量的请求,并在某个已知的固定时间重置它们。
如果他们用尽他们的API请求(即。计数器达到零或极限,这取决于您计数的方向),停止向他们提供数据,直到您重置他们的计数器。
这样的话,他们最大的利益就是不向你提出要求。
vq8itlhq4#
我不知道这个线程是否还活着,但我建议将这些统计数据保存在内存缓存中,比如memcached。这将减少将请求记录到数据库的开销,但仍能达到目的。
xmjla07d5#
你说“所有这些额外的开销在每个请求上都会破坏目的”,但我不确定这是正确的。目的不就是为了防止服务器瘫痪吗?这可能是我实现它的方式,因为它实际上只需要快速读/写。如果担心性能问题,您甚至可以将API服务器检查外包到不同的DB/磁盘。
然而,如果你想要替代方案,你应该看看mod_cband,一个第三方apache模块,旨在帮助带宽限制。尽管主要用于带宽限制,但它也可以基于每秒请求数进行节流。我从来没有使用过它,所以我不知道你会得到什么样的结果。还有另一个名为mod-throttle的模块,但该项目现在似乎已经关闭,并且从未为Apache 1.3系列以上的任何版本发布过。
rseugnpd6#
除了从头开始实现之外,你还可以看看API基础设施,比如3scale(http://www.3scale.net),它可以进行速率限制以及一系列其他东西(分析等)。这里有一个PHP插件:https://github.com/3scale/3scale_ws_api_for_php。
你也可以在API前面贴一些类似Varnish的东西,然后像这样限制API速率。
wswtfjt77#
难道这不能通过一次会议来完成吗?
比较
microtime()
和$_SESSION['last_access_microtime']
。sdnqo3pr8#
在node js中,有一个名为expess-rate-limiter的包,它正在做你想要完成的事情。
它限制了一段时间内的请求数量。我不知道PHP中是否也有同样的东西。