Using the Node.js Cluster Module to Improve Server Performance
Welcome back.
Now that we understand the theory behind clustering, let's explore how to apply the Node.js cluster module to our servers and improve their performance. In this document, we'll modify our performance example code to create two worker processes that handle requests concurrently.
Step-by-Step Guide to Implement Clustering
1. Requiring the Cluster Module
To use the cluster module, start by requiring it in your server file:
const cluster = require('cluster');
2. Master and Worker Processes
When you execute your Node.js application (e.g., node server.js
), a master process is created. This master process is responsible for creating worker processes.
The master and worker processes can be distinguished using the isMaster
boolean property provided by the cluster module:
if (cluster.isMaster) { //in new versions it is cluster.isPrimary
console.log('Master process has started.');
// Fork workers
cluster.fork();
cluster.fork();
} else {
console.log('Worker process has started.');
// Code for worker processes (e.g., starting the server)
}
3. Forking Worker Processes
To create worker processes, call the cluster.fork()
method. Each call creates a new worker process:
if (cluster.isMaster) { //in new versions it is cluster.isPrimary
cluster.fork();
cluster.fork();
}
In this example, we fork two worker processes. Each worker runs the same code as the master process but focuses on handling incoming HTTP requests.
4. Listening in Worker Processes
Only the worker processes should start the server and listen for incoming requests. Use the isMaster
property to ensure this separation:
import express from 'express';
import cluster from 'cluster';
const app = express();
app.get('/route', (req, res) => {
res.send(`Route handled by process ${process.pid}`);
});
app.get('/timer', (req, res) => {
setTimeout(() => {
res.send(`Timer completed by process ${process.pid}`);
}, 9000);
});
if (cluster.isPrimary) {
console.log(`Master ${process.pid} is running`);
// Fork workers
cluster.fork();
cluster.fork();
} else {
console.log(`Worker ${process.pid} started`);
app.listen(3000, () => {
console.log(`Worker ${process.pid} is listening on port 3000`);
});
}
5. Testing Process IDs
To verify which process handles a specific request, use the process.pid
property. This will log the ID of the current process to demonstrate load sharing.
Running the Clustered Server
Start the server:
node server.js
You’ll see logs indicating the master process and the two workers have started:
Master process has started. Worker process 24730 has started. Worker process 24731 has started.
Open multiple browser tabs or use tools like Postman to send simultaneous requests to the
/timer
and/route
endpoints.Requests to
/timer
will take 9 seconds to complete but will be handled by different processes.Requests to
/route
will be processed immediately by whichever worker process is available.
Handling Browser Caching Issues
When testing server clustering, browsers like Chrome might reuse cached responses for identical requests. To avoid this:
Open the browser’s Developer Tools.
Navigate to the Network tab.
Enable the Disable Cache option.
Alternatively, use keyboard shortcuts (e.g.,
Ctrl+Shift+R
orCmd+Shift+R
) to refresh without caching.
Observing the Results
Send requests to
/timer
from two browser tabs:Both requests should take 9 seconds but be processed in parallel by different worker processes.
Logs will display different
process.pid
values for each request.
Send a request to
/route
while a/timer
request is being processed:- The
/route
request will return almost instantly, demonstrating that the server remains responsive.
- The
Example logs:
Master process has started.
Worker process 24730 has started.
Worker process 24731 has started.
Route handled by process 24730
Timer completed by process 24731
Key Takeaways
The Node.js cluster module allows single-threaded applications to utilize multiple CPU cores effectively.
Worker processes share the workload, improving the server’s responsiveness and performance.
The
isMaster
flag ensures code segregation between the master and worker processes.
In the next lesson, we’ll discuss best practices for using clustering in real-world applications. See you soon!