Scaling Node.js Applications With PM2 Clusters

pm2 cluster

Node js was built on top of the V8 JavaScript engine. And we all know javascript is single-threaded, and our app runs in a single thread. So the complete utilization of the system resources was not happening.   
When we have a computationally intensive logic that might potentially block that thread or when we have a sudden spike in our traffic that could potentially increase the latency of our services.

The node.js Cluster Module

The above issue can be solved with the help of the node.js Cluster module. The cluster modules create so many node application instances on separate workers (child processes) sharing port 8080 depending on the number of CPU cores available.

Let us take a simple node server as given below:

//server.js
const http = require("http");
http.createServer((req, res) => {
	res.writeHead(200);
	res.end("server endpoint hit");
}).listen(8080);

For implementing the cluster module, we have to wrap existing code with cluster logic as below:

//server.js
const http = require("http");
const os = require("os");
const cluster = require("cluster");
const cpuCores = os.cpus().length;
if (cluster.isMaster) {
 	let instance = 0;
 	while (instance < cpuCores) {
   		cluster.fork();
   		++instance;
 	}
} else {
 	console.log(`Child-process ${process.pid} started`);
 	http.createServer((req, res) => {
   		res.writeHead(200);
   		res.end("server endpoint hit");
 	}).listen(8080);
}


If we are running the application in an 8-core CPU system, the above clustering logic will create 8 separate worker instances(child process) sharing the same port thereby we are scaling the node.js application. 

Drawbacks of the above method:

  • We have to modify the existing code to implement clustering.
  • If a child process was terminated, the new one wouldn’t be spawned to take its place unless we handle the exit event on the cluster instance.

PM2 Clusters(PM2 Ecosystem)

PM2 clusters overcome the above drawbacks. PM2 uses the Node.js cluster module to scale node.js applications across all CPUs available, without any code modifications. 

Installing PM2

Before you can utilize PM2 to manage your Node.js application, you need to install its npm package first. Execute the command below to install pm2 globally on your computer:

npm install -g pm2

Create Config File

In the pm2 config file, we can set up pm2 to work in cluster mode, increase pm2 instances, post-deploy scripts, etc… 
For creating a pm2 ecosystem config file, we can execute the following command:

pm2 ecosystem

The above command will create a file named ecosystem.config.js in your application directory as given below.

//ecosystem.config.js
module.exports = {
 	apps: [
   		{
     		name: "demo-app",
     		script: "server.js",
     		instances: 0,
     		exec_mode: "cluster",
     		watch: ".",
   		},
 	],
 	deploy: {
   		production: {
     		user: "YOUR_SSH_USERNAME_HERE",
     		host: "YOUR_SSH_HOST_ADDRESS",
     		ref: "YOUR_GIT_BRANCH_REF (eg: origin/master)",
     		repo: "GIT_REPOSITORY",
     		path: "YOUR_DESTINATION_PATH_ON_SERVER",
     		"pre-deploy-local": "",
     		"post-deploy":"npm install && pm2 reload ecosystem.config.js --env production",
     		"pre-setup": "",
   		},
 	},
};


In the above file :

  • script: script path relative to pm2 start
  • exec_mode: "cluster" tells PM2 to use the Node.js cluster module to execute the code.
  • instances:0 when this is set to 0, PM2 will automatically spawn a number of child processes equal to the number of cores available in the CPU. Respawning to termination is handled by PM2 on its own.
  • "post-deploy": "npm install && pm2 reload ecosystem.config.js -env production" The pm2 reloads which will make a zero-downtime deployment by adopting a rolling deployment approach where the instances are stopped and launched with the latest changes one after the other.

Start Application With PM2

Next, We can start our node application with PM2 as given below command:

pm2 start ecosystem.config.js

Now PM2 will create a number of instances of applications utilizing the system’s available cores without modifying the existing code.

Monitoring application metrics

Once your application is up and running, you can use PM2's list, show, and monit subcommands to keep tabs on how well your application is performing. First off, list all the running applications on your server with the pm2 list as shown below:

pm2 list

Restarting the application

One of the advantages of using a process manager like PM2 to manage your Node.js application in production is its ability to automatically restart the application when accidents occur. You can also restart your application at any time with the restart subcommand. It kills the process and relaunches it afterward:

pm2 restart ecosystem.config.js

For more deep knowledge see PM2 documentation.

Related Blogs

call-stack-in-javascript

What is Call Stack in JavaScript

JavaScript Call Stack is a mechanism to keep track of multiple function calls and manage execution context. This article describes how the call stack works with examples.

Factory Design Pattern in JavaScript

Factory Design Pattern in JavaScript

Factory allows you to handle all the object creation in a centralized location which helps the code clean, concise, and maintainable. Understand deeply with examples.

event loop and callback queue

Event Loop and Callback Queue in JavaScript

The event loop keeps monitoring the call stack and callback queue for executing callback functions. Read more about web APIs, callback queue, microtask queue, event loops, and starvation.

Cannot read property of undefined in JavaScript

Cannot read property of undefined in JavaScript

The TypeError: Cannot read property of undefined occurs when we try to read a property on an undefined variable or when we try to access a property on a DOM element that doesn't exist.

Can't set headers after they are sent to the client

Can't set headers after they are sent to the client

Error “Can't set headers after they are sent to the client” occurs when an express.js application tries to send multiple responses for a single request.

Greatest Common Divisor (GCD) in JavaScript

Find greatest common divisor (GCD) in JavaScript

Find the Greatest Common Divisor(GCD) of two numbers using the Euclidean algorithm in javascript. Calculate GCD for a given integer array.

How to Fix error:0308010C:digital envelope routines::unsupported

How to Fix error:0308010C:digital envelope routines::unsupported

To fix the error:0308010C:digital envelope routines::unsupported, enable the legacy provider for Node.js by passing --openssl-legacy-provider flag to webpack.

Javascript

What are Parameters, Arguments and Arguments Object in JavaScript

In JavaScript, the terms parameters, arguments, and arguments object are related to functions. Explains what they are with examples.

ckeditor

How to Integrate Custom Build CKEditor5 with React

Explains how to create a custom build CKEditor5 and integrate with react with sample code.