一个简单的Node.JS基准测试

3

我想确定这个基准测试是否公平。目标是尝试查看Node.JS可以处理多少个并发连接与各种大小的有效负载。以下是代码。

var express = require('express');
var Sequelize = require('sequelize');
var fs = require('fs');
var app = express();


var data;

var filename = process.argv[2] || './start.json';
console.log("Using: " + filename);
data = fs.readFileSync(filename);

var blockSize = 250000;
app.get('/start', function (req, res) {
  // Break up data in blocks.  Works to super high concurrents.
  // for(var i = 0; i < data.length; i+=blockSize)
  //   res.write(data.slice(i, i+blockSize));  

   // Can only handle about 600 concurrent requests if datasize > 500KB
   res.send(data);
});



app.listen(3000, function () {
  console.log('Listing on 3000.');
});

根据评论所述,如果负载大小大于约500KB并且有500个并发,则在负载测试客户端处会出现“对等方重置连接”的情况。如果您将数据切片并以块写入,则可以在启动此行为之前支持更高的并发。Node和Express都表现出这种行为。


问题是大部分数据都在RAM中。所以对于大型负载来说,关键是memcpy()需要花费多长时间。这正是node无法很好处理的工作负载类型。Node被优化用于I/O,而不是RAM处理。如果将文件作为读取流打开并将其传输到客户端,您将获得更好的并发性能。这样做将几乎所有的负载转移到操作系统上,而不是node上,如果您使用的是Linux或Solaris,您将从优化的文件系统驱动程序中获得巨大的提升。 - undefined
另一方面,对于小负载来说,将数据保留在内存中通常可以获得更好的性能。所以这真的取决于具体情况。 - undefined
当数据大小变大时,CPU的使用率达到100%,这对于节点来说显然非常糟糕。 - undefined
2个回答

1
data = fs.readFileSync(filename);

同步方法会影响Node.js的性能。它会阻塞事件循环,导致所有请求的性能变得非常差。

可以尝试以下方法:

var express = require('express');
var Sequelize = require('sequelize');
var fs = require('fs');
var app = express();
var filename = process.argv[2] || './start.json';

var blockSize = 250000;
app.get('/start', function (req, res) {
  // Break up data in blocks.  Works to super high concurrents.
  // for(var i = 0; i < data.length; i+=blockSize)
  //   res.write(data.slice(i, i+blockSize));  

   // Can only handle about 600 concurrent requests if datasize > 500KB
   console.log("Using: " + filename);

   fs.readFile(filename, function (err, data) {
      if (err) throw err;
      res.send(data);
   });

});



app.listen(3000, function () {
  console.log('Listing on 3000.');
});

1
如果你注意到它发生在脚本开始时,确切地只有一次。重点不是对文件加载进行基准测试,而是对传输进行基准测试。因此,在服务器监听连接之前,数据已经存储在内存中。 - undefined

0
作为一种替代方案,你可以创建一个读取流并进行管道传输,以下是基于你的代码的示例。
var express = require('express');
var fs = require('fs');
var app = express();

var data;

var filename = process.argv[2] || './data.json';
console.log("Using: " + filename);
data = fs.readFileSync(filename);

var readStream = fs.createReadStream(filename);

app.get('/start', function (req, res) {
  // Can only handle about 600 concurrent requests if datasize > 500KB
  //res.send(data);
  readStream.pipe(res);
});

这是我另一个想法。根据它的性能,我愿意打赌 send() 在幕后执行这个操作。如果你将 readStream 的创建放在 /start 中,它的执行效果就跟发送原始流一样。 - undefined
可能是这种情况。我用两种解决方案进行了测试,结果非常相似。 - undefined
1
而且,更有趣的是,如果你处理一个大文件(30MB),它的表现甚至比在相同测试中的 Go 更好。出乎意料。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接