9

If I'm not mistaken, I remember the "event loop" model of asynchronous I/O (Node.js, Nginx) not being well-suited for the sake of serving large files.

Is this the case, and if so, are there methods around it? I'm considering writing a real-time file explorer / file server in Node, but files could be anywhere from 100MB to ~3GB. I would assume that the event loop would block until the file is completely served?

mak
  • 13,267
  • 5
  • 41
  • 47
Dan Simmons
  • 187
  • 1
  • 9

2 Answers2

21

No, it will not be blocked. node.js will read a file in chunks and then send those chunks to the client. In between chunks it will service other requests.

Reading files & sending data over the network are I/O bound operations. node.js will first ask the operating system to read a part of a file and while the OS is doing that node.js will service another request. When the OS gets back to node.js with the data, node.js will then tell the OS to send that data to the client. While the data is being sent, node.js will service another request.

Try it for yourself:

Create a large file

dd if=/dev/zero of=file.dat bs=1G count=1

Run this node.js app

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/');

Request http://127.0.0.1:8000/ several times and watch node.js handle them all.

If you're going to serve lots of large files, you may want experiment with differnt bufferSize values.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
mak
  • 13,267
  • 5
  • 41
  • 47
  • Perfect! That's excellent that you can even define the granularity of the buffer size. How would the event loop compare in performance for delivering said large files versus the multi-threaded fork approach? I imagine that there's some sort of sweet spot in terms of buffer size such that it would allow Node to cope with multiple simultaneous streams while still remaining responsive but also making meaningful progress. – Dan Simmons Aug 03 '11 at 17:42
2

If I'm not mistaken, I remember the "event loop" model of asynchronous I/O (Node.js, Nginx) not being well-suited for the sake of serving large files.

I think you stand correct that node.js is not optimized for serving big files. I advice you to have a look at Ryan Dahl's slides. Especially

Slide 14

Wow. Node sucks at serving large files. Well over 3 second responses for 256 kilobyte files at 300 concurrent connections.

Slide 15

What’s happening: V8 has a generational garbage collector. Moves objects around randomly. Node can’t get a pointer to raw string data to write to socket.

Slide 21

But the fact remains, pushing large strings to socket is slow.

Hopefully this can be mitigated in the future.

are interesting. Maybe this has changed, but I think it would probably be better to use NGinx to serve your static files(or maybe a CDN). I think you are misinformed that NGinx is bad at serving large files. Node.js is(was) a bad at this because of V8 garbage collection, not because of event-loop. Also this link might be interesting.

Alfred
  • 60,935
  • 33
  • 147
  • 186
  • 2
    Slide 18 shows that node.js is on par with nginx when serving Buffers (and files can be read as buffers). – mak Aug 03 '11 at 18:14
  • @Mak you are right about that :). But still I think that node.js is probably not the best for this! I wonder if this continues when the filesize even gets bigger! Even Ryan says that "pushing large strings to socket is slow." – Alfred Aug 03 '11 at 18:35
  • my curiosity with this question is more about READING (POST or PUT) large files from the request, and I think node.js would be a good choice. – Anatoly G Nov 07 '11 at 22:09