我正在尝试使用 Node.js 将大文件(500 MB)写入磁盘。我发现虽然前几个文件在几秒钟内写入(通常是 3 到 5 秒),但从第 10 个文件开始,事情往往会变慢(并且不会恢复)。
该设置由一个服务器组成,该服务器通过 TCP/IP 套接字接受文件并将它们通过管道传输到磁盘:
var fs = require('fs'),
net = require('net'),
path = require('path');
var counter = 0;
net.createServer(function (socket) {
console.time('received');
console.time('written');
counter++;
var filename = path.join(__dirname, 'temp' + counter + '.tmp');
var file = fs.createWriteStream(filename, { encoding: 'utf8' });
socket.pipe(file);
socket.once('end', function () {
console.timeEnd('written');
});
file.once('finish', function () {
console.timeEnd('received');
});
}).listen(3000);
nc
我使用以下方式从终端发送数据:
$ while [ true ]; do `cat input.tmp | nc localhost 3000`; done
跑步
$ time cat input.tmp > /dev/null
已经表明 cat 总是在同一时间读取文件。如果我也将 Node.js 脚本的输出路径替换为/dev/null
写作,总是同时发生。
所以这个问题显然与实际写入磁盘有关。
我一开始以为可能是并发读写的问题,但是我跑的时候问题依然存在
$ while [ true ]; do `cat input.tmp | nc localhost 3000; sleep 5`; done
如果我使用更大的文件(两倍大,即 1 GByte)运行相同的测试,那么在写入变慢之前大约需要一半的时间。
更新
我已经更改了我的 Node.js 应用程序,将所有内容写入单个文件,该文件会不断地附加……服务器现在看起来像这样:
var fs = require('fs'),
net = require('net'),
path = require('path');
var filename = path.join(__dirname, 'temp.tmp');
var file = fs.createWriteStream(filename, { encoding: 'utf8' });
net.createServer(function (socket) {
console.time('received');
console.time('written');
socket.pipe(file, { end: false });
socket.once('end', function () {
console.timeEnd('written');
});
}).listen(3000);
现在问题消失了,显然它与连续写入多个文件有关。至少我看不到我同时在哪里写多个文件(是吗?),所以我想不出为什么会发生这种情况。特别是sleep 5
应该确保操作系统已经将所有内容真正写入磁盘。
更新 2
我最初使用 Node.js 0.10.32 进行测试。一旦我切换到 0.11.13,效果并没有完全消失,但它需要更多时间才能发生。在最初的设置中,问题出现在大约 10 个周期,Node.js 0.11.13 最早出现在第 30 个周期。
知道什么可能导致这种行为吗?