wpjscc / reactphp-limiter
用于Web和reactphp的通用速率限制器。适用于API客户端、网络爬虫或其他需要节流的任务。
v1.0.5
2023-08-25 08:13 UTC
Requires
- php: ^8.1
- react/async: ^4.1
- react/promise: ^3
Requires (Dev)
- phpunit/phpunit: ^9.5
This package is auto-updated.
Last update: 2024-09-09 05:37:43 UTC
README
为Web和node.js提供通用速率限制器。适用于API客户端、网络爬虫或其他需要节流的任务。暴露了两个类,RateLimiter和TokenBucket。TokenBucket提供了一种低级接口来进行速率限制,具有可配置的突发速率和滴答速率。RateLimiter位于TokenBucket之上,并添加了对每个间隔期间可以移除的最大令牌数的限制,以符合常见的API限制,如“每小时最多150个请求”。
安装
composer require wpjscc/reactphp-limiter
使用方法
一个简单的示例,每小时允许150个请求
use Wpjscc\React\Limiter\RateLimiter; use function React\Async\async; use function React\Async\await; // Allow 150 requests per hour (the Twitter search limit). Also understands // 'second', 'minute', 'day', or a number of milliseconds $limiter = new RateLimiter(150, "hour"); async (function sendRequest() { // This call will throw if we request more than the maximum number of requests // that were set in the constructor // remainingRequests tells us how many additional requests could be sent // right this moment $remainingRequests = await($limiter->removeTokens(1)); callMyRequestSendingFunction(...); })();
另一个示例,每250毫秒允许发送一条消息
use Wpjscc\React\Limiter\RateLimiter; use function React\Async\async; use function React\Async\await; $limiter = new RateLimiter(1, 250); async(function sendMessage() { $remainingMessages = await($limiter->removeTokens(1)); callMyMessageSendingFunction(...); })();
默认行为是在解析承诺之前等待当前生效的速率限制的时间长度,但如果您传入"fireImmediately": true
,承诺将立即解析,并将remainingRequests
设置为-1
use Wpjscc\React\Limiter\RateLimiter; use function React\Async\async; use function React\Async\await; $limiter = new RateLimiter( 150, "hour", true ); async(function requestHandler(request, response) { // Immediately send 429 header to client when rate limiting is in effect $remainingRequests = await($limiter->removeTokens(1)); if ($remainingRequests < 0) { $response.writeHead(429, {'Content-Type': 'text/plain;charset=UTF-8'}); $response.end('429 Too Many Requests - your IP is being rate limited'); } else { callMyMessageSendingFunction(...); } })();
RateLimiter和TokenBucket都提供了一个同步方法tryRemoveTokens()。这将立即返回一个布尔值,指示令牌移除是否成功。
use Wpjscc\React\Limiter\RateLimiter; use function React\Async\async; use function React\Async\await; $limiter = new RateLimiter(10,"second"); if ($limiter->tryRemoveTokens(5)) echo('Tokens removed'); else echo('No tokens removed');
要获取removeTokens
承诺之外的剩余令牌数,只需使用getTokensRemaining
方法。
use Wpjscc\React\Limiter\RateLimiter; use function React\Async\async; use function React\Async\await; $limiter = new RateLimiter(1, 250); // Prints 1 since we did not remove a token and our number of tokens per // interval is 1 echo($limiter->getTokensRemaining());
直接使用令牌桶在字节级别进行节流
use Wpjscc\React\Limiter\TokenBucket; use function React\Async\async; use function React\Async\await; define("BURST_RATE", 1024 * 1024 * 150); // 150KB/sec burst rate define("FILL_RATE", 1024 * 1024 * 50); // 50KB/sec sustained rate // We could also pass a parent token bucket in to create a hierarchical token // bucket // bucketSize, tokensPerInterval, interval const bucket = new TokenBucket( BURST_RATE, FILL_RATE, "second" ); async(function handleData($myData) use ($bucket) { await($bucket->removeTokens(strlen($myData)); sendMyData($myData); })();
附加说明
令牌桶和速率限制器都应该与消息队列或防止多次同时调用removeTokens()的方式一起使用。否则,如果较新的消息不断耗尽令牌桶,则较早的消息可能会被长时间挂起。这可能导致消息顺序错误或在高负载下出现“丢失”消息的情况。
许可
MIT许可