Node Core Modules Exploration - Cluster
Previously on on blog, i went into an overview of the Child Processes module. This time, we talk about about something that is sort of related to child_process.fork
, Clusters.
In fact, looking at the code for Clusters, child_process.fork
is actually required.
So what is the cluster thing anyway. Well Node.js is single threaded. So to take advantage of computers that have multiple cores(which is basically everything now), you can use the cluster module to create child processes that share server ports.
For example, lets take a look at a clustered http server.(this is taken from the official docs)
'use strict';
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
cluster.on('online', (worker) => {
console.log(`Master: ${process.pid}, worker ${worker.process.pid} is online`);
});
} else {
// Workers can share any TCP connection
// In this case it is an HTTP server
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
console.log(`Child Cluster ID
${cluster.worker.process.pid}`);
}).listen(8000);
}
Here, the cluster is sharing port 8000. Running this on my Late 2012 Macbook Pro, i get something like this when run:
Master: 72645, worker 72646 is online
Master: 72645, worker 72647 is online
Master: 72645, worker 72648 is online
Master: 72645, worker 72649 is online
I can kill any of those worker clusters without affecting the others.
How to cluster
So how do we exactly create a new cluster. We can see from the example above that we just have to call the cluster.fork
method from the master process. This will spawn a new worker process.
The Worker Class
The Worker class is the main class in the cluster module. It contains all the public info and methods about a worker.
There are 2 ways to get a handle on it. If you are in the Master process, you can just call cluster.workers
If you are in a worker(not the master process), then just use cluster.worker
.
Speaking of the Master process. How do we know that we are in the Master process? We use the isMaster
method from cluster
cluster.isMaster
You might be able to determine what this might return if it is the master cluster.
Also, all workers that are returned are just an instance of a Child Process.
Distribution of connections
You may be wondering how the cluster module determines how to distribute the incoming connections. There are 2 ways.
The first, which is the default(except for windows, sorry bro), is “Round Robin”. It is also smart enough not to overload any one process.
Just a note that the term “Round Robin” here refers to the programming term, not the round robin phase of the awesome Game Show “Supermarket Sweep”
Basically, the master worker, listens and accepts all incoming connections and then distributes them.
The Second, has the master worker creating the listener and givining it to workers that want to use it. Then those workers accept the incoming connections directly.
To change between the 2, set the cluster.schedulingPolicy
property with either cluster.SCHED_RR
(the default on non-windows) or cluster.SCHED_NONE
. This must be set before the first worker is spawned, after that, this value is then frozen.
It can all be set using the environment variable NODE_CLUSTER_SCHED_POLICY
using either rr
or none
It is important to note that there is no shared state between the workers, so relying heavily on in-memory data for session and login type stuff is not recommended.
Next
There are some more sophisticated things that you can do with cluster, so check out the docs.
Next time we will take a look at the Command Line Options(not really a module, but important, and its next on the list).