Node Js

Node.js Cluster Module — Load Balancer – Detailed Explanation

The Cluster Module allows a Node.js application to use multiple CPU cores by creating multiple Node.js processes (workers).

Why Cluster is Needed?

Node.js runs on a single thread.

Example:

const express = require("express");

const app = express();

app.listen(5000);

Even if your server has:

CPU Core 1
CPU Core 2
CPU Core 3
CPU Core 4
CPU Core 5
CPU Core 6
CPU Core 7
CPU Core 8

Node will use only:

CPU Core 1

The remaining cores stay idle.


Without Cluster

10000 Requests
|
v
Node Process
|
CPU Core 1

Problems:

High CPU Usage
Slow Response
Single Point Failure

With Cluster

                Master Process
|
-----------------------------------------
| | | |
Worker 1 Worker 2 Worker 3 Worker 4

Each worker is a separate Node.js process.


Basic Example

const cluster = require("cluster");
const os = require("os");

if (cluster.isPrimary) {

console.log("Master Process");

} else {

console.log("Worker Process");

}

Output:

Master Process

Because only one process exists.


Create Workers

const cluster = require("cluster");
const os = require("os");

const cpuCount = os.cpus().length;

if (cluster.isPrimary) {

console.log(`Master PID: ${process.pid}`);

for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}

}

Suppose machine has 8 cores.

Output:

Master PID: 1000

Worker PID: 1001
Worker PID: 1002
Worker PID: 1003
Worker PID: 1004
Worker PID: 1005
Worker PID: 1006
Worker PID: 1007
Worker PID: 1008

Full Express Example

const cluster = require("cluster");
const os = require("os");
const express = require("express");

const cpuCount = os.cpus().length;

if (cluster.isPrimary) {

console.log(`Master ${process.pid}`);

for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}

} else {

const app = express();

app.get("/", (req, res) => {

res.send(
`Response from Worker ${process.pid}`
);

});

app.listen(5000, () => {
console.log(
`Worker ${process.pid} started`
);
});

}

How Requests are Distributed?

Request 1 → Worker 1
Request 2 → Worker 2
Request 3 → Worker 3
Request 4 → Worker 4
Request 5 → Worker 1

This is Round Robin.

                Master
|
--------------------------------
| | | |
W1 W2 W3 W4

Master process distributes requests.


Worker Crash Recovery

Suppose:

Worker 3 Crashes

Without restart:

W1
W2
X
W4

Application capacity reduces.


Auto Restart Workers

const cluster = require("cluster");
const os = require("os");

const cpuCount = os.cpus().length;

if (cluster.isPrimary) {

for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}

cluster.on("exit", (worker) => {

console.log(
`Worker ${worker.process.pid} died`
);

cluster.fork();

});

}

Now:

Worker 1003 Died

New Worker 1010 Started

Self-healing system.


IPC (Inter Process Communication)

Workers can communicate with Master.

Worker:

process.send({
message: "User Created"
});

Master:

cluster.on("message",
(worker, message) => {

console.log(message);

});

Output:

User Created

Shared Memory?

Workers do NOT share memory.

Worker 1:

let counter = 10;

Worker 2:

console.log(counter);

Output:

undefined

Because:

Worker 1 Memory
Worker 2 Memory
Worker 3 Memory

are separate.


Problem Example

let onlineUsers = 0;

Request 1:

Worker 1
onlineUsers = 1

Request 2:

Worker 2
onlineUsers = 1

Actual users:

2

But each worker thinks:

1

Wrong data.


Solution

Store shared data in:

Redis

await redis.incr("onlineUsers");

MongoDB

await User.updateOne(...);

MySQL

UPDATE counter
SET total = total + 1;

Never store shared data in worker memory.


Cluster + MongoDB

Each worker creates its own connection pool.

Worker 1 → Mongo Pool
Worker 2 → Mongo Pool
Worker 3 → Mongo Pool
Worker 4 → Mongo Pool

Example:

mongoose.connect(
process.env.MONGO_URI,
{
maxPoolSize: 10
}
);

If 4 workers:

4 × 10 = 40 Connections

Need to size your database accordingly.


Cluster + Redis

Very common.

Users
|
Cluster Workers
|
Redis Cache
|
MongoDB

Benefits:

Fast
Shared Session
Shared Cache
Shared Counters

Real Example: Job Portal

Internet
|
v
Node Cluster
|
-----------------------------------
| | | |
W1 W2 W3 W4
|
Redis Cache
|
MongoDB

Flow:

User opens jobs page

Worker 2 receives request

Check Redis

Return cache

OR

Fetch MongoDB

Save Redis

Return result

Drawbacks of Cluster

1. Memory Usage

Each worker:

Express
Middleware
Routes
Models

are loaded separately.

Example:

1 Worker = 150 MB

8 Workers
= 1200 MB

2. Shared State Issue

Cannot use:

let counter = 0;

for global application state.

Need Redis/Database.


3. More Database Connections

More workers:

More DB Connections

Need proper pooling.


Cluster vs PM2

Cluster Module

You manage workers manually
You write cluster code

Example:

cluster.fork()
cluster.on("exit")

PM2

pm2 start server.js -i max

PM2 internally uses clustering and process management.

Benefits:

Auto Restart
Monitoring
Logs
Zero Downtime Deploy
Cluster Management

For production, most companies use:

Nginx
|
PM2 Cluster
|
Node.js
|
Redis
|
MongoDB/MySQL

Interview Answer

The Node.js Cluster Module allows a Node.js application to utilize multiple CPU cores by creating worker processes. A master process forks workers equal to the number of CPU cores and distributes incoming requests among them. Each worker runs its own event loop and memory space. Cluster improves throughput, CPU utilization, and fault tolerance, but shared state must be stored externally in systems like Redis, MongoDB, or MySQL. For production deployments, PM2 cluster mode is often preferred because it simplifies worker management and automatic restarts.