限制请求的速率限制算法

时间:2014-10-30 07:19:52

标签: algorithm service rate-limiting throttling

我需要为限制请求设计速率限制器服务。 对于每个传入请求,方法将检查每秒请求是否超过其限制。如果超过了它,它将返回等待处理所需的时间。

寻找一个简单的解决方案,它只使用系统滴答计数和rps(每秒请求数)。不应使用队列或复杂的速率限制算法和数据结构。

编辑:我将在c ++中实现它。另外,请注意我不想使用任何数据结构来存储当前正在执行的请求。 API就像:

if(!RateLimiter.Limit())    {        做工作        RateLimiter.Done();

}    其他        拒绝请求

3 个答案:

答案 0 :(得分:6)

最常用的算法是token bucket。没有必要发明新的东西,只需要搜索技术/语言的实现。

如果您的应用程序具有高可用性/负载平衡性,您可能希望将存储桶信息保留在某种持久性存储上。 Redis是一个很好的候选人。

我写的Limitd是一种不同的方法,是限制的守护进程。如果流量符合要求,应用程序会使用限制客户端询问守护程序。限制在限制服务器上配置,应用程序与算法无关。

答案 1 :(得分:0)

因为你没有提供任何语言或平台的提示,我只会给出一些伪代码..

你需要的东西

  • 当前正在执行的请求列表
  • 等待通知请求已完成

,代码可以像

一样简单
var ListOfCurrentRequests; //A list of the start time of current requests
var MaxAmoutOfRequests;// just a limit
var AverageExecutionTime;//if the execution time is non deterministic the best we can do is have a average

//for each request ether execute or return the PROBABLE amount to wait
function OnNewRequest(Identifier)
{
    if(count(ListOfCurrentRequests) < MaxAmoutOfRequests)//if we have room 
    {
        Struct Tracker
        Tracker.Request = Identifier;
        Tracker.StartTime = Now; // save the start time
        AddToList(Tracker) //add to list
    }
    else
    {
        return CalculateWaitTime()//return the PROBABLE time it will take for a 'slot' to be available
    }
}
//when request as ended release a 'slot' and update the average execution time
function OnRequestEnd(Identifier)
{
    Tracker = RemoveFromList(Identifier);
    UpdateAverageExecutionTime(Now - Tracker.StartTime);
}

function CalculateWaitTime()
{
    //the one that started first is PROBABLY the first to finish
    Tracker = GetTheOneThatIsRunnigTheLongest(ListOfCurrentRequests);
    //assume the it will finish in avg time
    ProbableTimeToFinish = AverageExecutionTime - Tracker.StartTime;
    return ProbableTimeToFinish
}

但请记住,这个

有几个问题
  • 假设通过返回等待时间,客户端将在传递的时间之后发出新请求。由于时间是一个估计,你不能用它来延迟执行,或者你仍然可以溢出系统
  • 由于您没有保留队列并延迟请求,因此客户可以等待他所需的更多时间。
  • 并且最后,由于您没有保留队列的任何内容,优先级和延迟请求,这意味着您可以拥有实时锁定,您可以告诉客户稍后返回,但是当他回来的时候已经取得了他的位置,他必须再次返回。

所以理想的解决方案应该是一个实际的执行队列,但是因为你不想要一个......我想这是下一个最好的事情。

答案 2 :(得分:0)

根据你的评论,你只需要一个简单的(不是非常精确的)每秒请求标志。在这种情况下,代码可以是这样的

var CurrentRequestCount;
var MaxAmoutOfRequests;
var CurrentTimestampWithPrecisionToSeconds
function CanRun()
{
    if(Now.AsSeconds > CurrentTimestampWithPrecisionToSeconds)//second as passed reset counter
        CurrentRequestCount=0;

    if(CurrentRequestCount>=MaxAmoutOfRequests)
        return false;

    CurrentRequestCount++
    return true;
}

似乎不是一种非常可靠的控制方法......但是......我相信这就是你所要求的......