我的网站的合法用户偶尔锤造成不良的后果API请求的服务器。我想提起的不超过一个极限说一个API调用每5秒或N每分钟话费(还没有想出确切的限制还)。我可以明明登录在DB每个API调用和做每个请求的计算,看看他们是否超过限制,但在每次请求所有这些额外的开销将是击败目的。什么是其他资源密集程度较低的方法,我可以用它来制定一个限制?我使用PHP /阿帕奇/ Linux的,对于它的价值。

有帮助吗?

解决方案

好了,有没有办法做我不问的任何的写入服务器,但我至少可以消除记录每一个请求。一种方式是通过使用“漏桶”节流方法,其中它仅跟踪的最后一个请求($last_api_request)和请求/限制的时间帧($minute_throttle)的数量的比率的。漏桶从未计数器复位(不像Twitter的API的油门其重置每小时),但如果桶已满(用户达到了极限),他们必须等待n秒桶空了一点,他们可以做的请求前。换句话说,它就像一个滚动的限制:如果有时间框架内上次请求,他们正在慢慢渗出了桶;它只是限制你,如果你装满铲斗。

此代码段将计算在每次请求一个新$minute_throttle值。我指定的的在$minute_throttle因为你可以任何时间段的增加油门,如每小时,每天,等...虽然比一个将很快开始新的混乱,为用户。

$minute = 60;
$minute_limit = 100; # users are limited to 100 requests/minute
$last_api_request = $this->get_last_api_request(); # get from the DB; in epoch seconds
$last_api_diff = time() - $last_api_request; # in seconds
$minute_throttle = $this->get_throttle_minute(); # get from the DB
if ( is_null( $minute_limit ) ) {
    $new_minute_throttle = 0;
} else {
    $new_minute_throttle = $minute_throttle - $last_api_diff;
    $new_minute_throttle = $new_minute_throttle < 0 ? 0 : $new_minute_throttle;
    $new_minute_throttle += $minute / $minute_limit;
    $minute_hits_remaining = floor( ( $minute - $new_minute_throttle ) * $minute_limit / $minute  );
    # can output this value with the request if desired:
    $minute_hits_remaining = $minute_hits_remaining >= 0 ? $minute_hits_remaining : 0;
}

if ( $new_minute_throttle > $minute ) {
    $wait = ceil( $new_minute_throttle - $minute );
    usleep( 250000 );
    throw new My_Exception ( 'The one-minute API limit of ' . $minute_limit 
        . ' requests has been exceeded. Please wait ' . $wait . ' seconds before attempting again.' );
}
# Save the values back to the database.
$this->save_last_api_request( time() );
$this->save_throttle_minute( $new_minute_throttle );

其他提示

可以控制与令牌桶算法时,这与漏桶的速率算法。请注意,您将有机会分享桶(即令牌量)超过工艺(或任何范围要控制)的状态。所以,你可能要考虑锁定,以避免竞争条件。

好消息:我做这一切为您:带宽节流/令牌桶

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();
}

我不知道如果这个线程仍然活着不是,但我会建议保持在内存中缓存就像memcached的这些统计信息。这将减少登记请求到数据库的开销,但仍达到目的。

最简单的解决办法是只给每个API密钥每24小时的请求的数量有限,并且在一些已知的,固定的,时间重置。

如果他们用尽他们的API请求(即计数器达到零,或限制,这取决于你正在计算方向),停止为他们提供服务的数据,直到重置他们的计数器。

这样,这将是的的最佳利益,不要求你锤

您说,“在每次请求所有的公益额外的开销会被打败的目的”,但我不知道这是正确的。是不是要阻止你的服务器的锤击的目的是什么?这可能是我会实现它,因为它真的只需要一个快速的读/写的方式。你甚至可以从农场的API服务器检查到不同的DB /盘,如果你担心性能。

不过,如果你想选择,你应该看看 mod_cband ,第三方Apache模块旨在协助带宽限制。尽管是主要用于带宽限制,它可以油门基于请求每秒为好。我从来没有使用过,所以我不知道你会得到什么样的结果。还有被称为另一个模块MOD油门为好,但该项目现在似乎被关闭,并没有发布以上在Apache 1.3系列的东西。

除了从头开始实施,你也可以看看像3比例API基础设施( HTTP://www.3scale达网络),其确实的速率限制,以及一个一堆其他的东西(分析等)。有一个为一个PHP插件: https://github.com/3scale/3scale_ws_api_for_php

您还可以坚持类似的API光油盈,做API速率限制类的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top