Improving NodeJS Performance with Clustering

Improving NodeJS Performance with Clustering

Scaling node applications can be tricky. It isn’t an easy topic. It requires lots of expertise both in terms of having knowledge about node nuances and how to manage resources. You can scale your application either by Vertical Scaling or by Horizontal scaling or by both. Apart from these, there are other factors that should be considered for better Node performance is either using ‘Cluster’ Mode or ‘Worker Threads’. We are going to focus on the ‘Cluster’ Mode.

Cluster Mode is used to start up multiple copies of nodes that are all running your server inside them. As we know that the Nodejs event loop is single-threaded, we cannot somehow trick the node into running multiple threads. But by starting up multiple copies we get multiple instances of the event loop. So it works in a similar fashion as it is kind of multi-threaded.

As soon as we start writing some Nodejs code that takes some amount of time to execute. Our entire server is blocking any other request that is coming in. And it can do absolutely nothing else until that original request gets resolved and handled. Imagine, how it can hamper entire application when there is 100 such other request in a queue.

Clustering comes to rescue…

Clustering in Node.js allows you to create separate processes which can share the same server port. It will take advantage of all core available on the machine. It will cluster the application and run them on all cores. So if one server goes down the other instance is ready to take the place of it. Even in heavy traffic, Node will automatically allocate the worker resource and manage internal load balancing. When we are going to use clustering inside a node application. We are going to create one parent process or kind of sheet anchor process called Cluster Manager.

Role of Cluster Manager:

  • It is responsible for monitoring and tracking the health of individual instances of our application that we are going to launch at the same time on our computer.
  • Cluster manager can start and stop instances. It can send the data. It can do other administrative stuff of managing resources i.e instances.

Single-Threaded Node Server:

withoutcluser-1.jpeg

app.get(“/someResource”, (req, res) => { 
  res.send(“Your Response”);
});

Multi-Threaded Node Server(using Clustering):

clusterinstance.jpeg

After app.js, cluster manager is the first node instance. The cluster manager is responsible for processing incoming requests to create this worker instance. The cluster manager is going to require in the cluster module from the node standard library. There is a particular function on the cluster module called ‘fork’. When we call ‘fork’ node internally goes back to app.js and executes it the second time. But when it executes the file a second time then starts up our worker instance.

    const cluster = require('cluster’); // cluster is a standard library module.
    console.log(cluster.isMaster);  //It return false for the first time.

The cluster manager that runs after app.js has the property isMaster property always set to true. But as soon as we are going to fork. Its property isManger is going to set false. We know as soon as children are fork by cluster manager app.js is executed again. One thing to note is that we can create multiple copies of our application using cluster.fork(). Its creation is dependent on the number of cores available on your machine.

    const cluster = require('cluster');
    if (cluster.isMaster) {
        cluster.fork();
        cluster.fork();
        cluster.fork(); //You can create multiple instances according to the cores available on your system.
    } else {
        const express = require('express');
        const app = express();
        app.get('/', (req, res)=>{
            res.send('Hello');
        });
        app.listen(3000);
    }

If we have some routes, that usually takes a long time to process. You have another route that is very quick. Then by using clustering, you can start multiple instances of your server. One instance will handle the heavy processing route and the other instance will handle the light processing route.

    app.get(‘/’, (req, res) => {
           //Some heavy processing
    });

    app.get(“/somelightprocessing’, (req, res) => {
           //Some light processing
    });

This way we can use Node clustering to improve the performance of your application. We can benchmark the performance of each cluster using a tool like 'PM2'.

I hope this article helps.

Note: This blog was originally written by me on kiprosh.com

References:

Did you find this article valuable?

Support AbulAsar S. by becoming a sponsor. Any amount is appreciated!