UDP在Node.js中发送性能
我正在用一个Java UDP客户端进行基准testing,该客户端可以尽可能快地连续发送100个字节的数据报。 它是使用java.nio.*
。 testing表明,它能够实现每秒220k数据报的稳定吞吐量。 我没有使用服务器进行testing。 客户端只是将数据报发送到本地主机上的一些未使用的端口。
我决定在Node.js中运行相同的testing来比较这两种技术,看到Node.js执行速度比Java慢10倍 ,这令人惊讶。 让我引导你通读我的代码。
首先,我使用Node.js的dgram模块创build一个UDP套接字:
var client = require('dgram').createSocket("udp4");
然后我创build一个使用该套接字发送数据报的函数:
function sendOne() { client.send(message, 0, message.length, SERVER_PORT, SERVER_ADDRESS, onSend); }
variablesmessage
是一个由应用程序启动时具有一百个字符的string创build的缓冲区:
var message = new Buffer(/* string with 100 chars */);
发送函数只是递增一个variables,该variables保存到目前为止发送了多less个数据报。 接下来,我有一个使用setImmediate()
不断调用sendOne()
的函数:
function sendForever() { sendOne(); setImmediate(sendForever); }
最初我尝试使用process.nextTick(sendForever)
但是我发现它总是把事件队列放在事件队列的顶端,甚至在IO事件之前,正如文档所说 :
它在任何其他I / O事件(包括定时器)在事件循环的随后滴答中触发之前运行。
这样可以防止发送 IO事件的发生,因为nextTick
在每次打勾时都会不断地将sendForever
放在队列的顶端。 队列随着未读IO事件增长,直到它使Node.js崩溃:
fish: Job 1, 'node client' terminated by signal SIGSEGV (Address boundary error)
另一方面, setImmediate
在I / O事件callback之后触发,这就是为什么我使用它。
我还创build了一个计时器,每1秒打印一次到控制台在最后一秒发送了多less个数据报:
setInterval(printStats, 1000);
最后我开始发送:
sendForever();
运行在与Javatesting相同的机器上,Node.js实现了每秒21k数据报的稳定吞吐量, 比Java慢十倍 。
我的第一个猜测是把两个sendOne
的每一个滴答,看看是否会增加吞吐量:
function sendForever() { send(); send(); // second send setImmediate(sendForever); }
但是它并没有改变吞吐量。
我有一个在GitHub上提供的完整的代码库:
https://github.com/luciopaiva/udp-perf-js
只需将其克隆到您的机器上,进入文件夹并运行:
node client
我想打开关于如何在Node.js中改进此testing的讨论,以及是否有某种方法可以提高Node.js的吞吐量。 有任何想法吗?
PS:对于那些感兴趣的,这里是Java的一部分 。
那个testing是过度的缺陷。 UDP不保证交付任何东西,并不保证在错误的情况下会给出任何错误。
您的应用程序可以从Java应用程序以1GB / s的速度发送1000k个数据报,但90%的数据报从未到达目的地…目标可能甚至没有运行。
如果你想做任何types的UDPtesting,你需要两个应用程序,每个应用程序一端。 发送编号数据报1,2,3 …并检查发送的内容和接收的内容。 请注意,UDP不保证消息的顺序。
内核以特殊的方式pipe理本地主机networking。 有巨大的缓冲区专用于它和更高的限制,没有stream量通过任何网卡或驱动程序。 这与真正发送数据包有很大不同。
当他们只在本地主机上完成时,testing可能看起来有些不错。 期待所有的事情都会在经历任何实际的基础设施时惨遭失败。
PC1 <-----> switch <-----> PC2
比方说,同一个房间里有两台电脑通过交换机连接起来。 在这个简单的设置上实现10k / s的UDP数据报是一件不小的功夫,不会随机丢失消息。
而这只是在同一个房间里的两台电脑。 在互联网和长途上可能会差很多。