我网站的合法用户有时会通过API请求对服务器进行锤击,从而导致不良结果。我想建立一个限制,即每5秒不超过一个API调用或每分钟不超过n个调用(尚未知道确切的限制)。显然,我可以将每个API调用记录在数据库中,并对每个请求进行计算,以查看它们是否超出限制,但是每个请求上的所有这些额外开销都无法达到目的。我可以使用哪些其他耗费资源较少的方法来建立限制?我正在使用PHP / Apache / Linux,这是值得的。
好的,没有对服务器的 任何 写操作就无法完成我所要求的操作,但是至少可以避免记录每个请求。一种方法是使用“泄漏桶”节流方法,该方法仅跟踪最后一个请求($last_api_request)和时间范围内请求数/限制的比率($minute_throttle)。泄漏的存储区永远不会重置其计数器(与每个小时都会重置的Twitter API的油门不同),但是如果存储区已满(用户已达到限制),则他们必须等待n几秒钟以使存储区清空,然后才能发出另一个请求。换句话说,这就像一个滚动限制:如果在时间范围内有先前的请求,它们正在缓慢地从存储桶中泄漏出去;仅在您加满水桶时才限制您。
$last_api_request
$minute_throttle
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 );