Re: [nodejs] Serving static files to slow clients

149 views
Skip to first unread message

Tim Caswell

unread,
Oct 10, 2012, 4:11:19 PM10/10/12
to nod...@googlegroups.com
I find that using a simple Stream.prototype.pipe from the file stream
to the response stream works equally great for fast and slow clients.
What really speeds things up is making sure to implement conditional
and partial requests. (If-Modified-Since, If-No-Match, Range, ...)

Node's stream pipe will handle back-pressure properly, it has fairly
large data chunks by default and will almost always be faster than the
socket it's writing to.

On Wed, Oct 10, 2012 at 11:29 AM, Michael Nutt <mic...@movableink.com> wrote:
> I'm in a situation where I'm serving a handful of 1MB static files to
> clients. We have our logic that determines which file to serve in node, so
> putting nginx or varnish in front of our node app isn't a great solution.
> Our first naive attempt was to load the entire file into a Buffer and cache
> each one for 60 seconds, and when a client connected we would just
> res.end(buffer).
>
> This worked fine up until yesterday, when a small number of slow clients
> caused our app to fall over due to what I think was the kernel send buffer
> filling up. I looked around for a buffer-to-stream implementation that
> would be able to read a file off the disk in a single shot into a buffer,
> then repeatedly stream it to later clients, but I couldn't find anything.
> Here's what I ended up writing:
>
> https://gist.github.com/3866612
>
> For the first client who requests the file, I call
> file.pipe(cachedStream).pipe(response), then store cachedStream in memory.
> For later clients, I can call cachedStream.pipeCached(response);
>
> It seems to work but is (acceptably) slower than the naive implementation
> for fast clients. My questions are: is there a reason none of the current
> static file implementations use something like this? Are there obvious
> problems with it? And is there an optimal bufferSize setting for sending to
> web clients, or is it solely based on the speed of the clients?
>
> Thanks,
> Michael
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to
> nodejs+un...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en

Johnny Honestly

unread,
Oct 10, 2012, 4:25:48 PM10/10/12
to nod...@googlegroups.com
stream master J has this pause stream which you could probably hack to do your thing

Bert Belder

unread,
Oct 10, 2012, 8:37:20 PM10/10/12
to nod...@googlegroups.com


On Wednesday, October 10, 2012 6:29:51 PM UTC+2, Michael Nutt wrote:
I'm in a situation where I'm serving a handful of 1MB static files to clients.  We have our logic that determines which file to serve in node, so putting nginx or varnish in front of our node app isn't a great solution. Our first naive attempt was to load the entire file into a Buffer and cache each one for 60 seconds, and when a client connected we would just res.end(buffer).

That sounds like a great way to do it. I would stick to it if you can.

This worked fine up until yesterday, when a small number of slow clients caused our app to fall over due to what I think was the kernel send buffer filling up.

That doesn't sound very plausible. The kernel send buffer fills up all the time; node takes care of handling that.

I think it is more likely that you ran out of file descriptors. If you are on linux (or another unix-like OS) and you haven't done so already, try to up it with "ulimit".

How did the the app "fall over"? Did it crash with an error? Did it just stop serving files? Spin? Crash?

- Bert


Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

Michael Nutt

unread,
Oct 11, 2012, 11:53:55 AM10/11/12
to nod...@googlegroups.com
Hi Bert,

I was getting a bunch of different errors:
node: ../src/tcp_wrap.cc:353: static void node::TCPWrap::AfterConnect(uv_connect_t*, int): Assertion `req_wrap->object_.IsEmpty() == false' failed.
Unknown system errno 105
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit. (never had these before)

The app wasn't using excessive memory or CPU, but it would respond to requests really slowly or not at all.  Monit would start it, it would run for ~2-10 seconds, then crash with one of the first two above.

During that time I tried to do a 'git pull' which led to warnings about the socket send buffer being full, and led me down this path.  But on second thought, I think I jumped to that conclusion too quickly.  I just checked our nofile limits and they were set at 1024 so it's definitely possible we ran out of file descriptors.

Thanks,
Michael

Ben Noordhuis

unread,
Oct 11, 2012, 12:28:55 PM10/11/12
to nod...@googlegroups.com
On Thu, Oct 11, 2012 at 5:53 PM, Michael Nutt <mic...@movableink.com> wrote:
> I was getting a bunch of different errors:
> node: ../src/tcp_wrap.cc:353: static void
> node::TCPWrap::AfterConnect(uv_connect_t*, int): Assertion
> `req_wrap->object_.IsEmpty() == false' failed.
> Unknown system errno 105

On what platform and with what version of node.js is this? You should
never hit asserts in C++ code.

Michael Nutt

unread,
Oct 11, 2012, 10:45:42 PM10/11/12
to nod...@googlegroups.com
This was node v0.8.0 on linux x86_64.  Admittedly an old version, and I'll file a bug report if I can ever manage to reproduce it on v0.8.11.
 
Reply all
Reply to author
Forward
0 new messages