DEV Community

Sarva Bharan
Sarva Bharan

Posted on

Scaling Node.js with the Cluster Module

The Cluster module allows Node.js to leverage multi-core systems, improving app performance. Let's explore how to use it effectively.

Why Cluster?

  1. Utilize all CPU cores
  2. Improve app responsiveness
  3. Increase reliability through worker redundancy

Basic Usage

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

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

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

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('Hello World\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}
Enter fullscreen mode Exit fullscreen mode

Load Balancing

Node.js handles load balancing automatically using a round-robin approach.

Inter-Process Communication (IPC)

if (cluster.isMaster) {
  const worker = cluster.fork();
  worker.send('Hi there');
} else {
  process.on('message', (msg) => {
    console.log('Message from master:', msg);
  });
}
Enter fullscreen mode Exit fullscreen mode

Zero-Downtime Restarts

if (cluster.isMaster) {
  cluster.on('exit', (worker, code, signal) => {
    if (!worker.exitedAfterDisconnect) {
      console.log('Worker crashed. Starting a new worker');
      cluster.fork();
    }
  });

  process.on('SIGUSR2', () => {
    const workers = Object.values(cluster.workers);
    const restartWorker = (workerIndex) => {
      const worker = workers[workerIndex];
      if (!worker) return;

      worker.on('exit', () => {
        if (!worker.exitedAfterDisconnect) return;
        console.log(`Exited process ${worker.process.pid}`);
        cluster.fork().on('listening', () => {
          restartWorker(workerIndex + 1);
        });
      });

      worker.disconnect();
    };

    restartWorker(0);
  });
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Use worker_threads for CPU-intensive tasks
  2. Implement proper error handling in workers
  3. Monitor worker health and restart if necessary
  4. Use a process manager like PM2 for production

Pitfalls to Avoid

  1. Sharing server handles explicitly (Node.js does this automatically)
  2. Overusing IPC (can become a bottleneck)
  3. Neglecting to handle worker crashes

Cluster module is powerful for horizontal scaling, but use judiciously. Always profile to ensure it's solving your specific performance needs.

Cheers🥂

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs