简化Node.js服务器的速率限制algorithm

我想出了一个针对Node.js服务器速率限制algorithm的天真解决scheme,我相信有一种方法可以简化它,但我不确定如何。

我们希望限制每秒50个请求。 所以如果最新的请求进来,最近的请求和50个位置之间的时间间隔小于1秒,我们应该拒绝新的请求。

实现这一点的天真的方法是有一个简单的数组,包含50个时间戳。 每次事件进来时,我们都给它赋值Date.now()/ process.hrtime()。 然后,我们查看队列中第50个(最后一个)时间戳的时间戳值以及新请求的Date.now()值,如果时间戳的差值大于1秒,那么我们接受新的请求并将其解除“队列”,并从队列中popup最早的时间戳。 但是,如果差值小于1秒,我们必须拒绝这个请求,而且我们也不会将其转移到队列中,也不会popup最早的时间戳。

这是我在Express服务器上的代码

var mostRecentRequestsTimestamps = []; app.use(function(req,res,next){ if(req.baymaxSource && String(req.baymaxSource).toUpperCase() === 'XRE'){ var now = process.hrtime(); //nanoseconds if(mostRecentRequestsTimestamps.length < 50){ mostRecentRequestsTimestamps.unshift(now); next(); } else{ var lastItem = mostRecentRequestsTimestamps.length -1; if(now - mostRecentRequestsTimestamps[lastItem] < 1000){ // 1000 milliseconds = 1 second res.status(503).json({error: 'Server overwhelmed by XRE events'}); } else{ mostRecentRequestsTimestamps.pop(); mostRecentRequestsTimestamps.unshift(now); next(); } } } else{ next(); } }); 

正如你所看到的,它只是阻止来自某个特定源的事件,所以它不应该饿死其他types的请求。 这个逻辑需要50个时间戳的数据结构,基本上什么都没有,但是如果可能的话,我想要一个更简化的方法。 有人有主意吗? 谢谢

这是最简单的我可以做到的:

 // oldest request time is at front of the array var recentRequestTimes = []; var maxRequests = 50; var maxRequestsTime = 1000; app.use(function(req,res,next){ if(req.baymaxSource && String(req.baymaxSource).toUpperCase() === 'XRE'){ var old, now = Date.now(); recentRequestTimes.push(now); if (recentRequestTimes.length >= maxRequests) { // get the oldest request time and examine it old = recentRequestTimes.shift(); if (now - old <= maxRequestsTime) { // old request was not very long ago, too many coming in during that maxRequestsTime res.status(503).json({error: 'Exceeded 50 requests per second for XRE events'}); return; } } } next(); }); 

这在概念上与您的实施有两种不同的方式:

  1. 我使用recentRequestTimes数组,以增加顺序(只是使我的编程大脑更合乎逻辑)
  2. 我总是将每个请求添加到数组中,即使它超载。 你没有计算超载的请求,我认为是错误的。 这也简化了代码,因为您可以在函数的开始处添加当前时间,然后只处理数组。