【发布时间】:2014-02-01 02:55:23
【问题描述】:
如果我没记错的话,我记得异步 I/O(Node.js、Nginx)的“事件循环”模型不适合处理大文件。
是这样吗,如果是这样,有没有办法解决它?我正在考虑在 Node 中编写一个实时文件资源管理器/文件服务器,但文件可能在 100MB 到 ~3GB 之间。我会假设事件循环会阻塞,直到文件完全服务?
【问题讨论】:
如果我没记错的话,我记得异步 I/O(Node.js、Nginx)的“事件循环”模型不适合处理大文件。
是这样吗,如果是这样,有没有办法解决它?我正在考虑在 Node 中编写一个实时文件资源管理器/文件服务器,但文件可能在 100MB 到 ~3GB 之间。我会假设事件循环会阻塞,直到文件完全服务?
【问题讨论】:
不,它不会被阻止。 node.js 将以块的形式读取文件,然后将这些块发送到客户端。在块之间,它将为其他请求提供服务。
通过网络读取文件和发送数据是 I/O 绑定操作。 node.js 将首先要求操作系统读取文件的一部分,并且在操作系统执行此操作时,node.js 将服务另一个请求。当操作系统将数据返回到 node.js 时,node.js 将告诉操作系统将该数据发送到客户端。在发送数据时,node.js 将处理另一个请求。
自己试试吧:
创建一个大文件
dd if=/dev/zero of=file.dat bs=1G count=1
运行这个 node.js 应用程序
var http = require('http');
var fs = require('fs');
var i = 1;
http.createServer(function (request, response) {
console.log('starting #' + i++);
var stream = fs.createReadStream('file.dat', { bufferSize: 64 * 1024 });
stream.pipe(response);
}).listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
多次请求http://127.0.0.1:8000/ 并观察node.js 处理它们。
如果您要提供大量大文件,您可能需要尝试不同的 bufferSize 值。
【讨论】:
如果我没记错的话,我记得异步的“事件循环”模型 I/O(Node.js、Nginx)不适合服务 大文件。
我认为你的观点是正确的,node.js 没有针对提供大文件进行优化。我建议你看看 Ryan Dahl 的 slides。特别是
幻灯片 14
哇。 Node 不擅长提供大文件。超过 3 秒的响应 对于 300 个并发连接的 256 KB 文件。
幻灯片 15
发生了什么:V8 有一个分代垃圾收集器。移动 随机周围的物体。节点无法获得指向原始字符串数据的指针 写入套接字。
幻灯片 21
但事实仍然存在,将大字符串推送到套接字是很慢的。
希望这可以在未来得到缓解。
很有趣。也许这已经改变了,但我认为使用 NGinx 来提供静态文件(或者可能是 CDN)可能会更好。我认为您误认为 NGinx 不擅长提供大文件。 Node.js 在这方面(曾经)很糟糕,因为 V8 垃圾收集,而不是因为事件循环。 this link 也可能很有趣。
【讨论】: