UDP在Node.js中发送性能

问题描述 投票:23回答:2

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

我决定运行Node.js的同样的测试,比较这两种技术,这是令人惊讶的伤心地看到,Node.js的比Java执行慢10倍。让我带您浏览我的代码。

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

var client = require('dgram').createSocket("udp4");

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

function sendOne() {
    client.send(message, 0, message.length, SERVER_PORT, SERVER_ADDRESS, onSend);
}

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

var message = new Buffer(/* string with 100 chars */);

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

function sendForever() {
    sendOne();
    setImmediate(sendForever);
} 

最初我尝试使用process.nextTick(sendForever),但我发现它总是把自己放在事件队列的顶端,甚至在IO事件之前,就像文档says

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

这可以防止发送IO事件发生,因为nextTick在每次滴答时不断将sendForever放在队列的尖端。队列随着未读IO事件而增长,直到它使Node.js崩溃:

fish: Job 1, 'node client' terminated by signal SIGSEGV (Address boundary error)

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

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

setInterval(printStats, 1000);

最后我开始发送:

sendForever();

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

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

function sendForever() {
    send();
    send();  // second send
    setImmediate(sendForever);
}

但它并没有改变吞吐量。

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

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

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

node client

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

P.S。:对于那些感兴趣的人,这里是Java part

node.js udp benchmarking
2个回答
1
投票

该测试有瑕疵。 UDP不保证任何内容的传递,并不保证在出现错误时会出现任何错误。

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

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

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

当它们仅在localhost上完成时,测试可能看起来有点好。当它通过任何真实的物理基础设施时,一切都会失败。

PC1 <-----> switch <-----> PC2

比方说,同一个房间里有两台电脑通过交换机连接起来。在这种简单的设置上实现10k / s UDP数据报并不随意丢失消息将是不小的壮举。

那只是同一个房间里的两台电脑。互联网和长途电话可能会更糟糕。


0
投票

如果你想要的只是让性能测试变得更快,删除setImmediate调用并在第一次完成后执行下一次发送,即在send回调中,在我的慢速笔记本电脑上将其性能提高到每秒~10万次请求。

function send(socket, message) {
  socket.send(message, SERVER_PORT, (err) => {
    send(socket, message);
  });
}

const socket = require('dgram').createSocket('udp4');
const message = new Buffer('dsdsddsdsdsjkdshfsdkjfhdskjfhdskjfhdsfkjsdhfdskjfhdskjfhsdfkjdshfkjdshfkjdsfhdskjfhdskjfhdkj');
send(socket, message);
© www.soinside.com 2019 - 2024. All rights reserved.