1

我正在尝试将保持活动从服务器发送到一堆 tcp 客户端。为了减少响应的服务器负载,我想将保持活动分开。

如果我有 3000 个 tcp 客户端,并且保持活动间隔为 60 秒,我需要在 60 秒内错开保持活动消息并每秒发送 50 个保持活动。

假设:

  1. 大量 tcp 连接(以千计)
  2. Tcp 连接持续存在,预计至少会活跃几个小时
  3. 如果客户端不再连接,服务器需要在 60 秒内知道
  4. 来自服务器和客户端的其他信息将来回发送
  5. 来自客户端的保持活动返回消息包含有用的数据(我认为排除了 UDP)

目前,我的想法是将我的 tcp 连接存储为标准的 javascript 对象,并将一些 id 映射到特定的连接本身。然后,每一秒,我都会得到这个对象的键数组,并将保持活动状态发送到其中的某些部分。

这是一个好方法吗?有没有更好的方法或其他我应该考虑的事情?

我最初解决问题的示例代码:

var KEEP_ALIVE_INTERVAL = 1000; // time between groups
var KEEP_ALIVE_CYCLE = 3; // number of groups
var tcp_conns = {
    a:"a",
    b:"b",
    c:"c",
    d:"d",
    e:"e",
    f:"f",
    g:"g",
    h:"h",
    i:"i"
};

var intervalCounter = 0;
setInterval(function() {

    console.log("sending keep alives intervalCounter="+intervalCounter);

    var numConns = Object.keys(tcp_conns).length;
    var connFactor = Math.ceil( numConns / KEEP_ALIVE_CYCLE );
    var lowerLimit = connFactor*intervalCounter-1;
    var upperLimit = connFactor*(intervalCounter+1);

    console.log("connFactor="+connFactor+", limits=["+lowerLimit+","+upperLimit+"]");

    // Is this even async???
    var keys = Object.keys(tcp_conns)
    for (var i = 0; i < keys.length; i++) {
        if(i>lowerLimit && i<upperLimit){
            var key = keys[i]
            var val = tcp_conns[key]
            console.log(" id="+key+" => "+val);
        }
    }

    intervalCounter++;
    if(intervalCounter==KEEP_ALIVE_CYCLE){
        intervalCounter=0;
    }
}, KEEP_ALIVE_INTERVAL);
4

1 回答 1

1

我不是显式管理包含所有连接的集合,而是每 45 秒到 75 秒随机发送一次保持活动。这样,keep-alives 将随着时间的推移而传播。我不确定以下代码是否按原样工作,但您会了解基本概念。

  • 我假设“PONG”作为一个单独的块到达,但情况可能并非如此。
  • 小心避免泄漏听众。在这里,我在发送 PING 时添加了一个“数据”处理程序,并在收到 PONG 时将其删除。不是最有效的解决方案。

这是代码:

var KEEP_ALIVE_TIMEOUT = 120*1000,
    MIN_KEEP_ALIVE = 45*1000,
    MAX_KEEP_ALIVE = 75*1000;

function randomInt(min, max) {
    return Math.random()*(max - min) + min;
}

net.createServer(function(conn) {
  function ping() {
     var keepAliveTimer = setTimeout(function() {
       conn.destroy();
       console.log('timeout !');
     }, KEEP_ALIVE_TIMEOUT);

     conn.write('PING\r\n');

     conn.on('data', function onData(chunk) {
        if(chunk.toString() !== 'PONG\r\n')
          return handleSomethingElse();

        clearTimeout(keepAliveTimer);
        conn.removeListener('data', onData);
        setTimeout(ping, randomInt(MIN_KEEP_ALIVE, MAX_KEEP_ALIVE));
     });
  }

  ping();
});
于 2012-08-09T17:33:17.010 回答