Guides and tutorials

Hundreds of tutorials and step by step guides carefully written by our support team.

How to scale Node.js applications with clustering

Introduction

Node.js is a server-side JavaScript runtime environment used to create scalable, high-speed web applications. Scalability is a critical factor for any web application that intends to handle large volumes of traffic. One of the most popular ways to scale Node.js applications is through the use of clustering.

Clustering is a technique that involves creating multiple Node.js processes that work together to handle the load of the application. This means that each request coming into the application is distributed across different processes so that they can be processed simultaneously. It also helps ensure that the application is fault tolerant and will continue to run even if one of the processes fails.

In this manual, we will explain how to set up clustering and how to scale your Node.js application with it.

Step 1: Install Node.js

Before you start, make sure you have Node.js installed on your system. You can download it from the official Node.js website and install it on your system.

Step 2: Create a Node.js application file

Create a Node.js application file that listens for client requests. This file will be the entry point for your application.

const http = require('http');
const server = http.createServer((req, res) => {
  res.end('Hello World!');
});
server.listen(3000);

Step 3: Configure such an application in cluster mode

Here's an example of a basic Node.js application running in cluster mod:

// app.js

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master process ID: ${process.pid}`);

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // Handle worker exit and restart
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker process ID ${worker.process.pid} died`);
    console.log('Forking a new worker...');
    cluster.fork();
  });
} else {
  // Worker processes will enter this block
  // Create a simple HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('Hello, world!\n');
  }).listen(3000);

  console.log(`Worker process ID ${process.pid} started`);
}

In this example, the master process is responsible for forking the worker processes, while the worker processes create an HTTP server and handle incoming requests. Each worker process listens on the same port (3000 in this case), allowing them to share incoming traffic.

Let's go through each part of the code and explain its purpose Vamos a repasar cada parte del código y explicar su propósito:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
  • The cluster module allows us to create and manage a cluster of worker processes.
  • The http module provides functionality to create an HTTP server.
  • The os module is used to determine the number of CPU cores available in the system using the cpus().length. property
if (cluster.isMaster) {
  console.log(`ID del proceso maestro: ${process.pid}`);

  // Crear procesos trabajadores
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // Manejar la salida y reinicio de los procesos trabajadores
  cluster.on('exit', (worker, code, signal) => {
    console.log(`El proceso trabajador con ID ${worker.process.pid} ha finalizado`);
    console.log('Creando un nuevo proceso trabajador...');
    cluster.fork();
  });
} else {
  // Los procesos trabajadores entrarán en este bloque
  // Crear un servidor HTTP básico
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('¡Hola, mundo!\n');
  }).listen(3000);

  console.log(`El proceso trabajador con ID ${process.pid} ha comenzado`);
}
  • The if (cluster.isMaster) block is executed only in the master process. It checks if the current process is the master process using the isMaster property of the cluster module.
  • If it is the master process, it prints to the console the ID of the master process using process.pid and then proceeds to create several worker processes.
  • The for loop creates the desired worker processes (in this case, numCPUs, representing the number of CPU cores).
  • The cluster.on('exit', ...) block handles the exit of the worker processes. Each time a worker process terminates (exits), the worker process ID is recorded in the console and a new worker process is created to replace it.
  • If the current process is not the master process (i.e., it is a worker process), it enters the else block.
  • Within the else block, each worker process creates an HTTP server using http.createServer() and listens on port 3000.
  • The server responds with a "Hello, world!" message for each request received.
  • The worker process ID is displayed in the console using process.pid to indicate that the worker process has started.

With this configuration, the master process is in charge of managing the worker processes. It creates them based on the number of available CPU cores and restarts any worker process that terminates. The workers processes handle incoming HTTP requests and respond to them. By distributing the load among the workers processes, the application can handle more concurrent requests and improve performance.

Feel free to modify the code according to your requirements and application logic.

Step 4: Run the application

  1. Save the above code in a file called app.js.

  2. Open the terminal and navigate to the directory containing app.js.

  3. Launch the application using the command node:

    $ node app.js
    

Step 5: Test the application

Test the application by opening a web browser and typing the IP address of the server and the port on which the application is running.

http://localhost:3000

Conclusion

Clustering is a popular technique for scaling Node.js applications. This manual has demonstrated how to set up and use clustering to distribute application load across multiple child processes. By following these steps, you will be able to scale your Node.js application and make it more resilient to failures.