mobly/connectopus-throttling

Token Bucket 算法的实现。由 Mobly 分支。

0.0.1 2018-09-19 14:36 UTC

This package is auto-updated.

Last update: 2024-09-20 06:11:43 UTC


README

这是 PHP 中 Token Bucket 算法的线程安全实现。您可以使用 Token Bucket 来限制资源的使用率(例如,流带宽或 API 使用)。

Token Bucket 是一个抽象的隐喻,没有资源消耗的方向。即您可以限制消耗或生产的速率。例如,您可以限制第三方 API 服务的消耗速率,或者限制您自己的 API 服务的使用速率。

安装

使用 Composer

composer require bandwidth-throttle/token-bucket

使用方法

该软件包位于命名空间 bandwidthThrottle\tokenBucket

示例

以下示例将限制全局资源每秒10个请求的速率。

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

echo "API response";

注意:在此示例中,TokenBucket::bootstrap() 是代码的一部分。这不建议在生产环境中使用,因为这会产生不必要的存储通信。应该将 TokenBucket::bootstrap() 作为应用程序的引导或部署过程的一部分。

存储范围

首先,您需要决定资源的范围。也就是说,您是否想按请求、按用户或对所有请求进行限制?您可以通过选择一个具有所需范围的 Storage 实现。

  • RequestScope 仅在单个请求内限制速率。例如,限制下载的带宽。每个请求都将具有相同的带宽限制。

  • SessionScope 限制会话内资源的速率。速率控制在一个会话的所有请求上。例如,限制每个用户的 API 使用。

  • GlobalScope 限制所有进程(即请求)的资源速率。例如,限制所有进程的资源总下载带宽。此范围允许进程之间发生竞争条件。因此,TokenBucket 在共享互斥锁上同步。

TokenBucket

拥有存储后,您可以最终实例化一个 TokenBucket。第一个参数是桶的容量。即不会提供更多令牌。这也意味着消耗超过容量的令牌是无效的。

第二个参数是 token-add-Rate。它决定了填充桶的令牌速度。速率是单位时间内添加的令牌数量,例如 new Rate(100, Rate::SECOND) 将每秒添加 100 个令牌。

第三个参数是存储,用于持久化桶的令牌数量。存储决定了桶的范围。

自举

需要一个令牌桶进行自举。虽然方法 TokenBucket::bootstrap() 对已自举的桶没有副作用,但不建议每次请求都调用它。更好的做法是在应用程序的自举或部署过程中包含这个。

消费

现在您已经有一个自举的桶,您可以开始消费令牌。方法 TokenBucket::consume() 将返回 true 如果令牌被消费,否则返回 false。如果令牌被消费,您的应用程序可以继续提供资源。

否则,如果令牌没有被消费,不应提供资源。在这种情况下,consume() 将将秒数写入其第二个参数(这是通过引用传递的)。这是足够令牌可用的时间。

BlockingConsumer

在第一个示例中,我们要么提供服务,要么用HTTP状态码429失败。这实际上是一种非常资源高效的方式来限制API请求,因为它不会在您的服务器上保留资源。

然而,有时我们希望不失败,而是等待一会儿,然后继续提供服务。您可以通过使用 BlockingConsumer 来消费令牌桶来实现这一点。

use bandwidthThrottle\tokenBucket\Rate;
use bandwidthThrottle\tokenBucket\TokenBucket;
use bandwidthThrottle\tokenBucket\BlockingConsumer;
use bandwidthThrottle\tokenBucket\storage\FileStorage;

$storage  = new FileStorage(__DIR__ . "/api.bucket");
$rate     = new Rate(10, Rate::SECOND);
$bucket   = new TokenBucket(10, $rate, $storage);
$consumer = new BlockingConsumer($bucket);
$bucket->bootstrap(10);

// This will block until one token is available.
$consumer->consume(1);

echo "API response";

这将有效地将速率限制在每秒10个请求。但在这个案例中,客户端不需要担心429错误。相反,连接只是延迟到期望的速率。

许可证和作者

此项目免费,并受WTFPL许可。此项目的负责人是Markus Malkusch,电子邮件地址为markus@malkusch.de。

捐赠

如果您喜欢这个项目,并且愿意慷慨捐赠,请在此处捐赠一些比特币:1335STSwu9hST4vcMRppEPgENMHD2r1REK

Build Status