2. Node.js is single-threaded
● One thread per process
● Deliberate design decision to avoid semaphore/mutex and other locking mechanisms that
introduce complexity and hard-to-debug bugs into the code
● Drawback: Massively under-utilizes raw parallelism available with today’s 2, 4, 8, 16 [, …] core
systems
3. Approaches to Node.js execution on Multi-core
systems
1. Single threaded execution
2. Execution in single-core virtual machines with multiple virtual machines each behind a load
balancer
3. Clustering Node.js
a. Run as many processes as cores on a single node
5. What is Node.js Clustering?
● Node.js server consists of multiple processes
● We start the main process called the master process
● Master process starts and manages other processes called worker processes
● Worker processes do the actual work
● TCP connections are shared and a default load balancer is included transparently
6. Multi-core and Multi-process
● Multi-core with cluster is basically multi-process on a single machine using Node’s built in load
balancer which defaults to round robin scheduling
● Multi-process on multiple machines requires the use of an external load balancer such as nginx
7. Sample Project to test multi-core performance
● A simple app was generated using express generator
● A processing intensive root route was created to test performance under heavy load conditions
● Multi-core code using Node.js cluster module was added
8. Why Multi-core?
● throughput ~= single-threaded throughput x cores
● test command:
○ siege -c100 -t1M http://localhost:3000/
■ 1 million total hits with 100 concurrent at a time
11. Why Multi-core?
● Decrease in latency
● Test using node siege benchmarking
var siege = require('siege');
// run cpu bound service benchmark
siege()
.on(3000)
.for(1000).times
.concurrent(100)
.get('/')
.attack();
14. Cluster Semantics
● Very simple to use
● Reap multi-core performance benefits with only a few extra lines of code
● Code divided into two sections:
○ One for master process
○ One for worker processes
● Various events are available to communicate between master/workers
15. Cluster Example Code
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) { // true for master process
cluster.setupMaster({
exec: 'bin/www'
});
...
16. Cluster Example Code (contd.)
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('listening', function (worker, address) {
console.log('Worker id: ' + worker.id + ' listening at: ' +
JSON.stringify(address));
});
17. Cluster Example Code (contd.)
Object.keys(cluster.workers).forEach(function (id) {
console.log('Worker id: ' + id + ' with pid: ' +
cluster.workers[id].process.pid);
});
cluster.on('exit', function (worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died: Respawning...');
cluster.fork();
});
}
18. Cluster Considerations
● Place your Node.js behind a connection throttling proxy such as apache or nginx so that a
high load does not down the server completely
● Restart worker processes that die
● Refresh worker processes to avoid memory leaks
● Place a monitor such as forever to restart the master Node.js process in case it dies
19. PM2
● Utility based clustering solution, runs as daemon
● No need to write clustering code
● Just write single-core code and invoke it with PM2 indicating number of processes to create
○ pm2 start app.js -i 4
● Other useful commands such as runtime scaling available