php如何控制用户数,php-如何限制网站的API用户?

php-如何限制网站的API用户?

我网站的合法用户有时会通过API请求对服务器进行锤击,从而导致不良结果。 我想设置一个限制,即每5秒不超过一个API调用或每分钟不超过n个调用(尚未知道确切的限制)。 很明显,我可以将每个API调用记录在数据库中,并对每个请求进行计算,以查看它们是否超出限制,但是每个请求的所有这些额外开销都无法达到目的。 我可以使用哪些其他耗费资源较少的方法来建立限制? 我正在使用PHP / Apache / Linux,这是值得的。

6个解决方案

53 votes

好的,没有对服务器的任何写操作就无法完成我所要求的操作,但是至少可以避免记录每个请求。 一种方法是使用“泄漏桶”节流方法,该方法仅跟踪最后一个请求($minute_throttle)和该时间范围内请求/限制的数量之比(2734213242796114114945)。 泄漏的存储区从不重置其计数器(与每个小时都会重置的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 );

scotts answered 2020-02-05T13:32:00Z

8 votes

您可以使用令牌桶算法来控制速率,该算法与泄漏桶算法相当。 请注意,您将必须在进程(或您要控制的任何范围)上共享存储桶的状态(即令牌数量)。 因此,您可能需要考虑锁定以避免发生竞争状况。

好消息:我为您做了所有这些工作:带宽限制/令牌桶

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

}

Markus Malkusch answered 2020-02-05T13:32:25Z

4 votes

我不知道该线程是否仍然存在,但我建议将这些统计信息保留在内存缓存(如memcached)中。 这将减少将请求记录到数据库的开销,但仍然可以达到目的。

Kedar Joshi answered 2020-02-05T13:32:45Z

3 votes

最简单的解决方案是每24小时仅向每个API密钥提供有限数量的请求,然后在某个已知的固定时间重置它们。

如果他们用完了API请求(即计数器达到零或限制,具体取决于您要计数的方向),请停止为它们提供数据,直到您重置其计数器为止。

这样,不对您提出要求就会使他们最大的利益。

Lasse Vågsæther Karlsen answered 2020-02-05T13:33:14Z

1 votes

您说“每个请求的所有额外开销都会破坏目的”,但是我不确定这是正确的。 这不是防止服务器受到攻击的目的吗? 这可能是我实现它的方式,因为它实际上只需要快速读/写。 如果您担心性能,甚至可以将API服务器检查分发到其他数据库/磁盘。

但是,如果您需要替代方案,则应签出mod_cband,这是一个旨在帮助限制带宽的第三方apache模块。 尽管主要用于带宽限制,但它也可以基于每秒的请求进行限制。 我从未使用过它,所以不确定是否会获得什么样的结果。 还有一个名为mod-throttle的模块,但是该项目现在似乎已关闭,并且从未针对Apache 1.3系列以上的版本发布。

zombat answered 2020-02-05T13:33:39Z

1 votes

除了从头开始实施之外,您还可以查看API架构,例如3scale([http://www.3scale.net)],它可以进行速率限制以及许多其他功能(分析等)。 有一个PHP插件:[https://github.com/3scale/3scale_ws_api_for_php。]

您还可以在API的前端粘贴类似Varnish的内容,并进行API速率限制。

steve answered 2020-02-05T13:34:04Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值