If you are already using nodejs for a while, you might already know that, nodejs is by default made up with single threaded architecture. That means, all your application logic will be run as a single thread for any amount of traffic requests. So, whenever it’s doing one operation, it won’t be doing anything else at that moment, even if there is a new request at the same time, which will have to wait. It may sound terrifying, but with its event-driven architecture, its doing the job quite well, as soon as one golden rule is followed, which is ‘each operations in nodejs should be done using minimum CPU time usage’. All CPU-heavy operations should be done somewhere else.

Well, that sounds fair. As soon as we know and follow this accordingly, our app should be fine doing its work in single threaded mode. However, still, if we get a very high traffic, where several requests per second need to be handled as fast as possible, single threaded architecture won’t do much good at that point, restricting you from scaling your application. So, what do we do?

NodeJS Cluster To The rescue:

Well, there is no direct facility to create multiple thread in a single nodejs application process, but there is facility to create multiple process to bind under same server port and work in the same way independently. Nodejs ‘cluster’ module facilitate this in a very efficient manner. We can implement multi-process architecture with it easily.

Creating a simple worker process:

Cluster module follows the master-slave/parent-child paradigm. So, the first process that will be run, is the master process, and all the other process that it creates, are workers. Lets see a small code snippet:

var http = require("http"); var cluster = require('cluster'); if (cluster.isMaster) { var worker = cluster.fork(); } else { http.createServer(function(req, res){ res.end("Hello World"); }).listen(1337); }

As you can see here, we are checking if it’s the initial/master process by using ‘cluster.isMaster’ check. If so, we are forking a new process under it. Which will in turn will fall under ‘else’ block and create the child process, which does the actual work of server port binding. However, you may noticed that, the above code is going to create only two processes: one child and one master, where master is doing nothing else other than creating the child.

Creating multiple child processes and controlled by master:

Lets now move ahead a little to create more than one processes and make sure all of them get terminated if the master is terminated.

var http = require("http"); var cluster = require('cluster'); if (cluster.isMaster) { var workers = []; for(var i=0; i<5; i++) { workers.push(cluster.fork()); } process.on('SIGINT', function(){ console.log("exiting "+process.pid); for(var i=0; i<5; i++) { console.log("destroying "+worker.process.pid); workers[i].destroy(); } }); } else { console.log("Child process "+process.pid+" being created and listening to port 1337"); http.createServer(function(req, res){ res.end("Hello World"); }).listen(1337); }

As you can see here, we are creating five child processes now and all of them are listening to same 1337 port. Besides, here our master process is also doing some significant tasks of making sure that all workers are terminated properly when the master process has to be terminated, so that there is not orphan child processes going to be around in the system.

Now all of these processes will share the same server port and listen together, though only process will be served with the request. If at some point 4 of them are already bg doing something, it still has room for getting another requests by the fifth one.

Some more failure recovery tuning:

Lets do some more awesome things. Lets assume, for some reason, our nodejs app is buggy and can crash anytime. Normally, you will might consider something like supervisord to monitor such process so that they respawn/restarted again automatically on crash events, to make sure your application is always alive. However, we can do that here internally, taken care of by the master process. A small example to give you idea how to do this is here:

var child = cluster.fork(); cluster.on('exit', function (worker, code, signal) { //logging details about what happend child = cluster.fork();; });

Here, as soon as an exit event is observed, master process is creating another child process, so that, number of available processes are always be the same.

Making Your Life easier:

If you are wondering what if you could just tell very easily how many child processes to create and where to bind and all of these stuffs happens automatically? Yes, it’s quite possible, leaving you doing all of this staffs by yourself every time you create a nodejs application, you can consider using the clustered-node library, that I have created few days ago, which is both simple to use and eases migrating your existing nodejs app to multi-process mode.

Things To Remember:

Give Master Process Least Responsibility: It’s always recommended that, you shouldn’t give master process much responsibility as more responsibility means more risk to erroneous process, more chance to crash the master itself, leaving all children processes as orphans.

It’s always recommended that, you shouldn’t give master process much responsibility as more responsibility means more risk to erroneous process, more chance to crash the master itself, leaving all children processes as orphans. Don’t Just create many workers: You should consider original number of CPUs/cores while creating child processes. You shouldn’t just create several child processes on a single CPU core as they will share same computing power by context switching, which might make performance worse. General rule of thumb is number of child processes=number of cpu cores available.

Final Words:

Let me know if something isn’t clear of this tutorial via comments. Hope this will help you in some extent to start with nodejs cluster. Happy coding 🙂