令牌桶算法,限速javascript?

时间:2015-09-03 01:55:19

标签: javascript algorithm

我正在尝试编写一个算法来防止在8秒内发送超过5条消息,我在python中找到了令牌桶算法的公式,所以我试图用javascript实现它,但我错过了一件事。

last_check变量对我来说并不清楚。如果我在一分钟内跟踪60秒,问题就是在第59秒后循环回来时,数学被抛弃了。

第一次迭代

如果last_check = new Date().getSeconds()让我们说它跟踪的时间是33秒,我们现在比较的是33秒。

rateLimit()函数执行时,它获得调用时的current时间,例如消息,current new Date().getSeconds()为40秒.... last_check之后7秒

所以time_passed现在是7秒,last_checked变成了40。

津贴结果

allowance7 * (5.0/8.0) = 4.375

问题在哪里

如果last_checked保持在40,并且在新消息之前经过22秒,那么下面第二次迭代的公式就会变为。

第二次迭代

current变为2(40 + 22)new Date().getSeconds()循环回2 ... time_passed现在(2-40)= -38秒,last_checked现在是2。

津贴结果

allowance-38 * (5.0/8.0) = -23.75

var rate = 5.0; // unit: messages
var per = 8.0; // unit: seconds
var allowance = rate; // unit: messages
var last_check = new Date().getSeconds();

function rateLimit() {
    current = new Date().getSeconds(); // floating-point, e.g. usec accuracy. Unit: seconds
    time_passed = current - last_check;
    last_check = current;
    allowance += time_passed * (rate / per);

    console.log('Current time: ' + current);
    console.log('Time passed: ' + time_passed);
    console.log('Last check: ' + last_check);
    console.log('Allowance: ' + allowance);

    if (allowance > rate) {
        allowance = rate; // throttle
        console.log('throttle');
    }
    if (allowance < 1.0) {
        console.log('discard message');
        return false;
    } else {
        allowance -= 1.0;
        console.log('forward message');
        return true;
    }
}

http://jsfiddle.net/wxjfcm5d/47/

3 个答案:

答案 0 :(得分:2)

我同意@ Evilzebra的评论,即解决方案可能有点复杂。根据您所需的行为,我以这种方式实现:

var ii = 0;
var perMils = per * 1000;
function rateLimit() {
    if (ii <= rate) {
        ++ii;
        setTimeout(function() {--ii;}, perMils);
        return true;
    }
    return false;
}

答案 1 :(得分:1)

current - last_check中,您需要两个日期之间的差异,而不是秒针的位置之间的差异。

new Date().getSeconds()替换为new Date().getTime()/1000(或new Date().getTime(),但您必须将var per = 8.0替换为var per = 8000.0

这将导致current - last_check始终为正秒数(或毫秒),而不是在秒数转为分钟时为负数。

答案 2 :(得分:0)

您也可以使用我写过的flood-protection库。它使用Token Bucket Algorithm

用法

import FloodProtection from 'flood-protection';

const floodProtection = new FloodProtection({
    rate: 5, 
    // default: 5, unit: messages
    // IMPORTANT: rate must be >= 1 (greater than or equal to 1)

    per: 8, 
    // default: 8, unit: seconds
});

希望这有帮助。