我的网站的合法用户偶尔会向服务器发出API请求,导致不希望的结果.我想设定一个上限,不超过每5秒一次API调用或每分钟n次调用(尚未计算出确切的上限).很明显,我可以在数据库中记录每个API调用,并对每个请求进行计算,以查看它们是否超出了限制,但每个请求上的所有额外开销都将达不到目的.我还可以使用哪些资源密集度较低的方法来设定限制?我正在使用PHP/Apache/Linux,这是值得的.

推荐答案

好的,如果没有any次写入服务器,就无法完成我的请求,但我至少可以消除记录每个请求的功能.一种方法是使用"漏桶"节流方法,它只跟踪最后一个请求($last_api_request)和时间范围内请求数/限制的比率($minute_throttle).漏桶从不重置计数器(不像Twitter API的油门每小时重置一次),但如果桶满了(用户达到限制),他们必须等待n秒,让桶空一点,然后才能发出另一个请求.换句话说,这就像一个滚动限制:如果在时间范围内有以前的请求,它们就会慢慢地从桶中泄漏出来;只有当你把桶装满的时候,它才会限制你.

此代码段将在每个请求上计算一个新的$minute_throttle值.我在$minute_throttle中指定了minute,因为你可以在任何时间段添加节流,比如每小时、每天等等...虽然不止一个会很快让用户感到困惑.

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

Linux相关问答推荐

PERF显示不应该执行指令的内核的用户空间周期

JSON 转义 CURL/JQ 输出

我需要制作一个 awk 脚本来解析文件中的文本.我不确定我是否做得正确

有必要注意非错误提示吗?好像没有找到包裹‘***’?

我想使用排序命令对第 5 列进行日期排序.但问题是格式不一致,有什么方法可以做到吗?

在android上使用lldb-server进行lldb调试?

ftell 在文件描述符上?

如何将通配符参数传递给 bash 文件

具体来说,fork() 如何处理 Linux 中 malloc() 动态分配的内存?

用于将文件夹从本地计算机复制到远程服务器的 scp 命令语法

通过写入 /dev/input/mice 来控制鼠标

如何将输出从 grep 传送到 cp?

用于 Linux 的 Less 编译器

试运行 cron 条目

以原子方式移动目录

linux根据文件名模式搜索文件

初学者如何在 Linux 中开始使用 Mono?

我可以使用 awk 将所有小写字母转换为大写吗?

Bash 将 awk 的输出捕获到数组中

学习内核编程