UDP在Node.js中发送性能

Luc*_*iva 24 benchmarking udp node.js

我正在对Java UDP客户端进行基准测试,该客户端以尽可能快的速度连续发送具有100字节有效负载的数据报.它是使用实现的java.nio.*.测试表明,它能够实现每秒220k数据报的稳定吞吐量.我没有测试服务器; 客户端只是将数据报发送到localhost上的一些未使用的端口.

我决定在Node.js中运行相同的测试来比较这两种技术,看到Node.js的执行速度比Java快10倍,我感到非常难过.让我带您浏览我的代码.

首先,我使用Node.js的dgram模块创建一个UDP套接字:

var client = require('dgram').createSocket("udp4");
Run Code Online (Sandbox Code Playgroud)

然后我创建一个使用该套接字发送数据报的函数:

function sendOne() {
    client.send(message, 0, message.length, SERVER_PORT, SERVER_ADDRESS, onSend);
}
Run Code Online (Sandbox Code Playgroud)

该变量message是在应用程序启动时从包含一百个字符的字符串创建的缓冲区:

var message = new Buffer(/* string with 100 chars */);
Run Code Online (Sandbox Code Playgroud)

该函数onSend只增加一个变量,该变量保存到目前为止发送了多少数据报.接下来我有不断调用一个函数sendOne()使用setImmediate():

function sendForever() {
    sendOne();
    setImmediate(sendForever);
} 
Run Code Online (Sandbox Code Playgroud)

最初我试图使用,process.nextTick(sendForever)但我发现它总是把自己放在事件队列的顶端,甚至在IO事件之前,正如文档所说:

它在事件循环的后续滴答中触发任何其他I/O事件(包括定时器)之前运行.

这可以防止发送 IO事件发生,就像每次打勾时nextTick一直放在sendForever队列的尖端一样.队列随着未读IO事件而增长,直到它使Node.js崩溃:

fish: Job 1, 'node client' terminated by signal SIGSEGV (Address boundary error)
Run Code Online (Sandbox Code Playgroud)

另一方面,setImmediate在I/O事件回调后触发,这就是我使用它的原因.

我还创建了一个计时器,每1秒向控制台打印一次,在最后一秒发送了多少数据报:

setInterval(printStats, 1000);
Run Code Online (Sandbox Code Playgroud)

最后我开始发送:

sendForever();
Run Code Online (Sandbox Code Playgroud)

在运行Java测试的同一台机器上运行,Node.js实现了每秒21k数据报的稳定吞吐量,比Java慢十倍.

我的第一个猜测是sendOne为每个刻度线放两个,看它是否会使吞吐量加倍:

function sendForever() {
    send();
    send();  // second send
    setImmediate(sendForever);
}
Run Code Online (Sandbox Code Playgroud)

但它并没有改变吞吐量.

我在GitHub上有一个存储库,其中包含完整的代码:

https://github.com/luciopaiva/udp-perf-js

只需将其克隆到您的机器,cd进入该文件夹并运行:

node client
Run Code Online (Sandbox Code Playgroud)

我想开一个关于如何在Node.js中改进这个测试的讨论,如果有一些方法我们可以增加Node.js的吞吐量.有任何想法吗?

PS:对于那些感兴趣的人,这里是Java部分.

use*_*461 2

该测试存在飞越缺陷。UDP 不保证任何内容的传送,也不保证在发生错误时会给出任何错误。

您的应用程序可以从 Java 应用程序以 1GB/s 的速度发送 1000k 数据报/秒,但 90% 的数据报从未到达目的地...目的地甚至可能没有运行。

如果您想要进行任何类型的 UDP 测试,则需要两个应用程序,每一端一个。发送编号数据报 1、2、3... 并检查发送的内容和接收的内容。请注意,UDP 不保证消息的任何顺序。

内核以特殊方式管理本地主机网络。有专用于它的巨大缓冲区和更高的限制,没有流量经过任何网卡或驱动程序。这与真正发送数据包有很大不同。

当仅在本地主机上完成测试时,测试可能看起来还不错。当一切真正通过任何物理基础设施时,预计一切都会严重失败。

PC1 <-----> switch <-----> PC2
Run Code Online (Sandbox Code Playgroud)

比方说,同一个房间里有两台计算机通过交换机连接。在如此简单的设置上实现 10k/s UDP 数据报而不随机丢失消息将是一个不小的壮举。

这只是同一个房间里的两台计算机。在互联网和长途上情况可能会更糟。

  • 你在这里错过了重点。我很清楚UDP是如何工作的,我既不关心接收端是否能够处理数据报,也不关心网络连接是否能够无损地传输它们;这就是为什么我明确表示数据报被发送到一些未使用的本地端口。此讨论是关于在相同的外部条件(即相同的硬件、相同的操作系统等)下应用程序每秒能够触发多少个数据报。 (8认同)