【问题标题】:NodeJS and TCP performanceNodeJS 和 TCP 性能
【发布时间】:2015-06-03 10:58:16
【问题描述】:

我正在测试两个 NodeJS 实例之间通过 TCP 的通信,使用 net module

由于 TCP 不依赖消息 (socket.write()),我将每条消息包装在类似 msg "{ json: 'encoded' }"; 的字符串中,以便单独处理它们(否则,我会收到随机数为级联消息)。

我在 CentOS 6.5 VirtualBox VM 上运行两个 NodeJS 实例(服务器和客户端),该 VM 具有桥接网络和基于 Core i3 的主机。测试在于客户端向服务器发出请求并等待响应:

  1. 客户端连接到服务器。
  2. 客户端输出当前时间戳 (Date.now())。
  3. 客户端发出 n 个请求。
  4. 服务器回复 n 个请求。
  5. 客户端在每次响应时增加一个计数器。
  6. 完成后,客户端输出当前时间戳。

代码很简单:

服务器

var net = require('net');

var server = net.createServer(function(socket) {

    socket.setNoDelay(true);

    socket.on('data', function(packet) {

        // Split packet in messages.
        var messages = packet.toString('utf-8').match(/msg "[^"]+";/gm);

        for (var i in messages) {

            // Get message content (msg "{ content: 'json' }";). Actually useless for the test.
            //var message = messages[i].match(/"(.*)"/)[1];

            // Emit response:
            socket.write('msg "PONG";');

        }

    });

});

server.listen(9999);

客户

var net = require('net');

var WSClient = new net.Socket();

WSClient.setNoDelay(true);

WSClient.connect(9999, 'localhost', function() {

    var req = 0;
    var res = 0;

    console.log('Start:', Date.now());

    WSClient.on('data', function(packet) {

        var messages = packet.toString("utf-8").match(/msg "[^"]+";/gm);

        for (var i in messages) {

            // Get message content (msg "{ content: 'json' }";). Actually useless for the test.
            //var message = messages[i].match(/"(.*)"/)[1];

            res++;
            if (res === 1000) console.log('End:', Date.now());

        }

    });

    // Emit requests:
    for (req = 0; req <= 1000; req++) WSClient.write('msg "PING";');

});

我的结果是:

  • 1 个请求:9 - 24 毫秒
  • 1000 个请求:478 - 512 毫秒
  • 10000 个请求:5021 - 5246 毫秒

我对 localhost 的 ping (ICMP) 介于 0.6 - 0.1 秒之间。我没有过多的网络流量或 CPU 使用(运行 SSH、FTP、Apache、Memcached 和 Redis)。

这对于 NodeJS 和 TCP 是否正常,还是只是我的 CentOS VM 或我的低性能主机?我应该迁移到另一个平台,如 Java 还是原生 C/C++ 服务器?

我认为对于我的项目来说,本地主机上的每个请求延迟 15 毫秒(平均)是不可接受的。

【问题讨论】:

  • 我建议不要使用setNoDelay 并且有一个体面的消息解析器(因为对于较大的消息它会失败),也可以尝试流 V2 接口。如果您想要更高的性能,请尝试使用集群模块。
  • 另一件事 1k 请求在 500 毫秒内和 10k 在 5 秒内是一个相当好的结果,它大约是 2 个请求 / 毫秒,即请求延迟 0.5 毫秒,不是吗?
  • @Oriol 你能获得更好的性能吗?
  • @Vicb 不,我不能。我猜这些是“正常”的结果。
  • 我也在我的 mac 和 ec2 c3.xl 上做了同样的测试,它给了我同样的结果。如果您发现任何东西,请更新线程 tahnks。

标签: node.js tcp


【解决方案1】:

将消息包装在一些文本中并搜索正则表达式匹配是不够的。

net.Servernet.Socket 接口将原始 TCP 流作为底层数据源。只要底层 TCP 流有可用数据,data 事件就会触发。

问题是,您无法控制 TCP 堆栈。它触发data 事件的时间与您的代码逻辑无关。因此,您无法保证驱动您的听众的data 事件恰好有一个、少于一个、多于一个或任意数量和一些剩余的消息正在发送。事实上,您几乎可以保证底层 TCP 堆栈会将您的数据分解成块。并且侦听器仅在块可用时触发。您当前的代码在 data 事件之间没有共享状态。

您只提到了延迟,但我希望如果您检查一下,您还会发现(两端)收到的消息数不是您所期望的。那是因为通过它的任何部分消息都将完全丢失。如果 TCP 流在块 1 的末尾发送半条消息,而在块 2 中发送剩余的消息,则拆分消息将被完全丢弃。

简单而健壮的方法是使用像 ØMQ 这样的消息传递协议。您将需要在两个端点上使用它。它负责将 TCP 流构建成原子消息。

如果出于某种原因您将连接到外部来源或从外部来源接收流量,他们可能会使用长度标头之类的东西。然后,您要做的是创建一个转换流来缓冲传入流量,并且仅在标头中标识的数量到达时才发出数据。

【讨论】:

    【解决方案2】:

    你做过网络转储吗?由于启用“无延迟”套接字属性引入的开销,您可能会造成网络拥塞。此属性会尽快将数据向下发送到 TCP 堆栈,如果您的信息块非常小,它将导致许多 TCP 数据包的有效负载较小,从而降低传输效率并最终导致 TCP 因拥塞而暂停传输。如果您想对套接字使用“无延迟”,请尝试增加接收套接字缓冲区,以便更快地从 tcp 堆栈中提取数据。让我们知道这是否有帮助。

    【讨论】:

      猜你喜欢
      • 2016-10-25
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      • 2014-01-08
      • 2011-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多