Building A Node.js Server That Won't Melt
hacks.mozilla.org
hacks.mozilla.org
Interestingly, this is one piece of a broader strategy for building scalable web applications, addressed in Matt Welsh's thesis (SEDA):
http://www.eecs.harvard.edu/~mdw/proj/seda/
If you haven't taken a look at the ideas in SEDA, it's definitely worth the time. Most modern web apps incorporate at least some pieces of it to great effect.
// check if we're toobusy() - note, this call is extremely fast, and returns
// state that is calculated asynchronously.
if (toobusy()) res.send(503, "I'm busy right now, sorry.");
Saying it is calculated "asynchronously" seems pretty confusing in this context. Maybe "is cached at a fixed interval"?But agree that a higher level proxy is useful - because this way your overloaded application doesn't even need to deal with traffic (we hope to use toobusy to have applications instruct the routing layer to temporarily block / reroute traffic in times of load).
npm install toobusy
then somewhere in your project require("toobusy");
If you only need one server that's going to be up to a lot faster than putting anything in front of it.A single server setup might be simpler, but it won't be faster. Varnish serving a cached page from memory is going to be faster than 5 asynchronous calls that take 5ms of CPU time (and filesystem I/O in the case of the database and template given in the example). With varnish, even with a 1 second TTL (and 1 second grace), your first request will take the 5ms hit, but the next 199 for that second will be served from memory.
Now with Varnish serving 199 out of 200 requests from memory, if your backend is still toobusy, by all means serve a 503, and Varnish can cache that too.
I think that's how that quote goes.
var cache;
module.exports = function(request, response) {
if(cache) {
return response.end(cache);
}
// get my data from wherever
cache = the_data;
return response.end(cache);
}
Now 199 out of 200 requests are from memory, there are zero extra moving parts, and you're using a cool part of the language instead of a 3rd party tool you have to select and configure.Where it gets really fun with NodeJS is you can do all of your data work outside of the requests so you can pull all of your content out at the start and refresh it on an interval independently of the users, which can eliminate some or all of their trips to the database if you're lucky and it fits in ram and is viable etc.
The less moving parts that need to cooperate to serve your site the better - most things don't warrant a deep stack of technology to serve HTML and run CRUD operations.
Read up on Netflix's architecture, where they've talked about this a lot. And the book "Release It!: Design and Deploy Production-Ready Software" (Nygard), though Java-oriented in its examples, covers the concepts well.
[edit] I do get your point, I was just saying: don't start implementing a naive load-balancer :-)
The book's examples and text are all Java, but the lessons are applicable anywhere. He offers many scalability patterns (resource pools) and anti-patterns (runaway log files) with interesting stories from his experience debugging real systems. I especially liked his story about debugging a crash in an Oracle DB driver that caused unexpected Java exceptions to be thrown from java.sql.Statement.close(), which quickly blocked a DB connection pool.
IIS [1] and other mature web servers like nginx [2] or apache [3] do this kind of thing for you and provide simple configuration on it.
[1] http://support.microsoft.com/kb/943891 [2] http://serverfault.com/questions/412323/nginx-503-error-in-h... [3] http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxrequ...
Did you mean to link to MaxClients[1]? MaxClients sets the maximum number of simultaneous connections; any additional connections will be queued by the OS socket api (subject to listen backlog, etc).
I think waiting to accept sockets that you can't handle is a better solution than either accepting a socket to return an error message, or (much worse) accepting a socket that overloads your system. Unfortunately, sometimes it can be hard to set MaxClients to the right value that isn't so big that you get reduced througput, or too small that you don't use all your resources. (One thing that does help you get to the right number for MaxClients is to set MinSpareServers to the same value as MaxClients; you will avoid issues where MaxClients is too big and you start swapping during high load, but you don't notice it because things are fine with a small number of servers).
Sorry, that was way too much information.
[1] http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxclie...
A harder problem is to solve the same "melt-out" problem for the entire gamut of servers that are usually found in large serving stacks (various web servers, relattional and nosql db servers etc). The users are usually not the developers of these pieces of technology and there's never enough dev-bandwidth available to actually implement self-tuning techniques like the one mentioned here.
For such situations I once came up with a "little" trick to limit the damage in sudden overload situation. It allows the admins of said servers to tune the threadpool and request queue lengths in an intelligent way (with the help of historical performance data that most shops should have). I mentioned it in this discussion thread here: http://www.linkedin.com/groups/Whats-generally-used-methodol...
Are there some recommend resources I could learn more from about the out of the box scaling vs tactics and strategies that benefit growth? I love learning how this problem is tackled anywhere. :)
With all software having it's limits (assuming hw is relative) has a starting and ending point of when you need to start tweaking it, and in what direction. I was hoping to read more about that.
The trick of using event loop lag is pretty neat, but the general strategy is IMHO a must have for any service. By aborting early and somewhat gracefully, the user knows ASAP, receives a controlled message that suggests she should not quickly retry, and the server can avoid trying to do part of the work for the request that is not going to be completed.
Though you'd need a custom client, so maybe for appcache'd webapps or mobile apps, but not typical webapps. Or browser vendor participation (not serious (ok, half serious)).
https://gist.github.com/4532177#file-application_server-js-L...
how should I know? :)