Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 客户端请求速率限制_C#_.net_Rate Limiting - Fatal编程技术网

C# 客户端请求速率限制

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设计一个.NET客户端应用程序。它将有两个主要职责:

  • 同步-对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分钟
如果我的应用程序只是关于“同步”的,那么这是可以接受的,但是“客户端”请求不能等待那么久

我在网上搜索过,读过令牌/漏桶和滑动窗口算法,但我无法将它们转换到我的案例和.NET中,因为它们主要涉及拒绝超过限制的请求。我找到了和,但它们都是唯一的服务端解决方案

类似于QoS的速率拆分,因此“同步”的速率较慢,“客户端”的速率较快,这不是一个选项


假设将测量当前请求速率,如何计算下一个请求的延迟,以便它能够适应当前情况,尊重所有最大速率,并且不会超过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);