C# 客户端请求速率限制
我正在为外部API设计一个.NET客户端应用程序。它将有两个主要职责:C# 客户端请求速率限制,c#,.net,rate-limiting,C#,.net,Rate Limiting,我正在为外部API设计一个.NET客户端应用程序。它将有两个主要职责: 同步-对API发出一批请求并定期将响应保存到数据库 客户端-我的客户端用户向API请求的传递 服务文档规定了在给定时间段内可以发出的最大请求数的以下规则: 在一天中: 每小时最多6000个请求(~1.67/秒) 每分钟最多120个请求(每秒2个) 每秒最多3个请求 晚上: 每小时最多8000个请求(~2.23/秒) 每分钟最多150个请求(每秒2.5个) 每秒最多3个请求 超过这些限制不会导致立即锁定-不会引发异
- 同步-对API发出一批请求并定期将响应保存到数据库
- 客户端-我的客户端用户向API请求的传递
- 每小时最多6000个请求(~1.67/秒)
- 每分钟最多120个请求(每秒2个)
- 每秒最多3个请求
- 每小时最多8000个请求(~2.23/秒)
- 每分钟最多150个请求(每秒2.5个)
- 每秒最多3个请求
public async Task MyMethod(Request request)
{
await _rateLimter.WaitForNextRequest(); // awaitable Task with calculated Delay
await _api.DoAsync(request);
_rateLimiter.AppendRequestCounters();
}
最安全和最简单的选择是只遵守最低速率限制,即每2秒最多3个请求。但由于“同步”责任,需要尽可能多地使用这些限制
所以下一个选项是根据当前请求计数添加延迟。我试着自己做一些事情,我也用过,本来可以,但有个问题:
假设我的客户每天每秒向API发送3个请求,我们将看到:
- 每120次请求延迟20秒
- 每6000次请求延迟约15分钟
假设将测量当前请求速率,如何计算下一个请求的延迟,以便它能够适应当前情况,尊重所有最大速率,并且不会超过5秒?类似于在接近极限时逐渐减速。这可以通过使用您在GitHub上链接的库来实现。我们需要使用一个由3
CountByIntervalAwaitableConstraint
组成的复合时间限制器,如下所示:
var hourConstraint=new CountByIntervalAwaitableConstraint(6000,TimeSpan.FromHours(1));
var minuteConstraint=new CountByIntervalAwaitableConstraint(120,TimeSpan.frommins(1))
var secondConstraint=new CountByIntervalAwaitableConstraint(3,TimeSpan.FromSeconds(1));
var timeLimiter=timeLimiter.Compose(小时约束、分钟约束、秒约束);
我们可以通过这样做来测试这是否有效:
for(int i=0;i<1000;i++)
{
等待时限;
WriteLine($“Iteration{i}at{DateTime.Now:T}”);
}
这将每秒运行3次,直到达到120次迭代(迭代119),然后等待一分钟结束,然后继续每秒运行3次。我们还可以(再次使用库)通过使用提供的AsDelegatingHandler()
扩展方法,轻松地将TimeLimiter与HTTP客户端一起使用,如下所示:
var handler=TimeLimiter.Compose(hourConstraint、minuteConstraint、secondConstraint);
var client=新的HttpClient(处理程序);
我们也可以使用CancellationToken
s,但据我所知,不能同时将其用作HttpClient的处理程序。以下是如何将其与HttpClient
一起使用:
var timeLimiter=timeLimiter.Compose(小时约束、分钟约束、秒约束);
var client=新的HttpClient();
对于(int i=0;i<100;i++)
{
wait composed.Enqueue(异步()=>
{
var client=新的HttpClient();
var response=wait client.GetAsync(“https://hacker-news.firebaseio.com/v0/item/8863.json?print=pretty");
if(响应。IsSuccessStatusCode)
WriteLine(wait response.Content.ReadAsStringAsync());
其他的
WriteLine($“错误代码{response.StatusCode}原因:{response.ReasonPhrase}”);
},新的CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
}
编辑以解决运营问题更多:
如果您想确保用户无需等待限制结束即可发送请求,我们需要每秒钟/分钟/小时向用户发送一定数量的请求。因此,我们需要一个新的时间限制,并调整我们的API时间限制。以下是两个新的:
var apiHourConstraint=newcountbyintervalawaitableconstraint(5500,TimeSpan.FromHours(1));
var apimuteconstraint=new CountByIntervalAwaitableConstraint(100,TimeSpan.frommins(1));
var ApisSecondConstraint=new CountByIntervalAwaitableConstraint(2,TimeSpan.FromSeconds(1));
//自动调用API的TimeLimiter
var apitTimeLimiter=TimeLimiter.Compose(apiHourConstraint、apiMinuteConstraint、apiSecondConstraint);
var userHourConstraint=新CountByIntervalAwaitableConstraint(500,TimeSpan.FromHours(1));
var userMinuteConstraint=newcountbyintervalawaitableconstraint(20,TimeSpan.frommins(1));
var userSecondConstraint=newcountbyintervalawaitableconstraint(1,TimeSpan.FromSeconds(1));
//用户手动调用API的TimeLimiter
var userTimeLimiter=TimeLimiter.Compose(userHourConstraint、userMinuteConstraint、userSecondConstraint);