Load balancing helps spread tasks evenly across multiple workers so no single worker gets overwhelmed. This keeps your app fast and stable.
Load balancing between workers in Node.js
Start learning this pattern below
Jump into concepts and practice - no test required
import cluster from 'node:cluster'; import os from 'node:os'; if (cluster.isPrimary) { const cpuCount = os.cpus().length; for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`Worker ${worker.process.pid} died. Restarting...`); cluster.fork(); }); } else { // Worker code here // For example, start an HTTP server }
Use cluster.isPrimary to check if the code runs in the main process.
Use cluster.fork() to create a new worker process.
import cluster from 'node:cluster'; import os from 'node:os'; if (cluster.isPrimary) { cluster.fork(); } else { console.log('Worker started'); }
import cluster from 'node:cluster'; import os from 'node:os'; if (cluster.isPrimary) { const cpuCount = os.cpus().length; for (let i = 0; i < cpuCount; i++) { cluster.fork(); } } else { // Worker code }
cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died. Restarting...`); cluster.fork(); });
This program uses the cluster module to create one worker per CPU core. Each worker runs an HTTP server on port 8000. When you visit localhost:8000, the response shows which worker handled your request. If a worker crashes, the primary process restarts it automatically.
import cluster from 'node:cluster'; import http from 'node:http'; import os from 'node:os'; if (cluster.isPrimary) { const cpuCount = os.cpus().length; console.log(`Primary process ${process.pid} is running`); for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`Worker ${worker.process.pid} died. Restarting...`); cluster.fork(); }); } else { http.createServer((req, res) => { res.writeHead(200); res.end(`Handled by worker ${process.pid}\n`); }).listen(8000); console.log(`Worker ${process.pid} started`); }
Each worker runs independently and can handle requests simultaneously.
Use the cluster module only in the main entry file of your app.
Restarting workers on exit helps keep your app reliable.
Load balancing spreads work across CPU cores using workers.
The cluster module helps create and manage worker processes.
Workers can be restarted automatically if they crash.
Practice
cluster module in Node.js for load balancing?Solution
Step 1: Understand the role of the cluster module
The cluster module allows Node.js to create multiple worker processes that share the same server port.Step 2: Identify the purpose of load balancing
Load balancing means distributing incoming requests evenly across workers to use CPU cores efficiently.Final Answer:
To spread incoming requests across multiple CPU cores using worker processes -> Option AQuick Check:
Load balancing = spreading requests across workers [OK]
- Thinking cluster creates a single-threaded server
- Confusing load balancing with database management
- Assuming cluster compresses data for memory optimization
Solution
Step 1: Recall the cluster API properties
Node.js cluster module providesisMasterandisWorkerboolean properties to identify process roles.Step 2: Identify the correct property for master check
cluster.isMasteris true if the process is the master, so the condition should use this.Final Answer:
if (cluster.isMaster) { /* master code */ } -> Option CQuick Check:
Master check uses cluster.isMaster [OK]
- Using cluster.isWorker to check for master
- Using non-existent properties like cluster.master
- Confusing cluster.worker with cluster.isWorker
const cluster = require('cluster');
const http = require('http');
if (cluster.isMaster) {
cluster.fork();
cluster.fork();
} else {
http.createServer((req, res) => {
res.end(`Worker ${process.pid} handled request`);
}).listen(8000);
}
What will happen when you send multiple requests to port 8000?Solution
Step 1: Understand cluster.fork() behavior
Calling cluster.fork() creates worker processes that share the same server port.Step 2: Analyze request handling in workers
Both workers listen on port 8000 and Node.js load balances requests between them automatically.Final Answer:
Requests will be handled by both worker processes, distributing load -> Option AQuick Check:
Multiple workers share port and balance requests [OK]
- Thinking only one worker handles all requests
- Assuming master handles requests directly
- Believing server crashes due to port sharing
const cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork();
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
} else {
throw new Error('Crash');
}Solution
Step 1: Check the exit event handler
The master listens for 'exit' but only logs the death, it does not fork a new worker.Step 2: Identify missing restart logic
To restart workers after crash, the master must callcluster.fork()inside the exit event handler.Final Answer:
The master does not fork a new worker after exit event -> Option DQuick Check:
Restart requires forking new worker on exit [OK]
- Assuming worker error handling restarts process
- Thinking cluster import affects restart
- Believing exit event is attached incorrectly
Solution
Step 1: Fork workers equal to CPU cores in master
if (cluster.isMaster) { const cpuCount = require('os').cpus().length; for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, restarting...`); cluster.fork(); }); } else { require('http').createServer((req, res) => { res.end(`Handled by worker ${process.pid}`); }).listen(3000); } correctly usesos.cpus().lengthto fork that many workers in the master process.Step 2: Restart workers on exit event in master
if (cluster.isMaster) { const cpuCount = require('os').cpus().length; for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, restarting...`); cluster.fork(); }); } else { require('http').createServer((req, res) => { res.end(`Handled by worker ${process.pid}`); }).listen(3000); } listens to the 'exit' event on cluster and forks a new worker to replace the dead one.Step 3: Worker creates HTTP server listening on port 3000
if (cluster.isMaster) { const cpuCount = require('os').cpus().length; for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, restarting...`); cluster.fork(); }); } else { require('http').createServer((req, res) => { res.end(`Handled by worker ${process.pid}`); }).listen(3000); }'s else block creates the server in workers, which is correct for load balancing.Final Answer:
Forks workers across all CPU cores and automatically restarts workers if they crash -> Option BQuick Check:
Fork all CPUs + restart on exit = if (cluster.isMaster) { const cpuCount = require('os').cpus().length; for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, restarting...`); cluster.fork(); }); } else { require('http').createServer((req, res) => { res.end(`Handled by worker ${process.pid}`); }).listen(3000); } [OK]
- Not forking all CPU cores
- Not restarting workers after crash
- Forking workers inside worker process
- Attaching exit listener inside worker instead of master
