How to scale Node.js applications with clustering

Atualizado em 2026-10-24 19:01:28 16 visitas

Introduction

Node.js is a server-side JavaScript runtime environment used to create scalable and 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 by using clustering.

Clustering is a technique that involves creating multiple Node.js processes that work together to handle the application load. This means that each request arriving at 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 continues to run even if one of the processes fails.

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

Step 1: Install Node.js

Before starting, 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 said application in cluster mode

This is an example of a basic Node.js application that runs in cluster mode:

// 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!
');
  }).listen(3000);

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

In this example, the master process is responsible for forking 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), which allows them to share the incoming traffic.

We are going to review each part of the code and explain its purpose:

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 on the system using the cpus().length property.
if (cluster.isMaster) {
  console.log(`Master process ID: ${process.pid}`);

  // Create worker processes
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

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

  console.log(`Worker process with ID ${process.pid} has started`);
}
  • The if (cluster.isMaster) block runs 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 the master process ID to the console using process.pid and then proceeds to create several worker processes.
  • The for loop creates the desired worker processes (in this case, numCPUs, which represents the number of CPU cores).
  • The cluster.on('exit', ...) block is responsible for handling the exit of worker processes. Each time a worker process ends (exits), the worker process ID is logged to 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 exits. The worker processes handle incoming HTTP requests and respond to them. By distributing the load among the worker 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 previous code in a file named app.js.

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

  3. Start the application using the node command:

    $ node app.js
    

Step 5: Test the application

Test the application by opening a web browser and typing the server's IP address 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 shown how to configure and use clustering to distribute the application load across multiple child processes. By following these steps, you will be able to scale your Node.js application and make it more fault-tolerant.