Home > database >  How do you set up workers in a cluster using Node.js without having it in the same file?
How do you set up workers in a cluster using Node.js without having it in the same file?

Time:05-22

I have this code in an index.js that I mostly left unmodified from the official Node.js documentation.

const https = require('https');
const fs = require('fs');
const cluster = require('node:cluster');
const numCPUs = require('node:os').cpus().length;
const process = require('node:process');

const livegame = require('./server-livegame');
const matchmaking = require('./server-matchmaking');

//Start ExpressJS
var express = require('express');
const { match } = require('assert');

var app = express();
app.use(express.json());


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

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

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
  });
}
else
{
  new livegame;
  new matchmaking;
}

Here is a simplified code for livegame/matchmaking that produces the error.

const https = require('https');
const fs = require('fs');
const mongoose = require('mongoose');

//Import Models
const LiveMatch = require('./models/livematch');

//Start ExpressJS
var express = require('express');
const { match } = require('assert');

//Interface Security
var options = {
  key: fs.readFileSync('key.pem', 'utf8'),
  cert: fs.readFileSync('cert.pem', 'utf8')
};

//Server
var httpsServer = https.createServer(options, app);

httpsServer.listen(443);
var app = express();
app.use(express.json());

const chat = 
    {
        puuid: String,
        name: String,
        roleID: String,
        message: String,
    }

app.post(':id/chat', (req,res) => 
{
    //something here
});

I have livegame and matchmaking as separate .js files alongside the index.js whom I call to launch them programmatically as multiple instances. However, this is the error I get:

node:events:505
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE: address already in use :::443
    at Server.setupListenHandle [as _listen2] (node:net:1380:16)
    at listenInCluster (node:net:1428:12)
    at Server.listen (node:net:1516:7)
    at C:\Users\----\Documents\MG\src\server-matchmaking.js:25:66
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Emitted 'error' event on Server instance at:
    at emitErrorNT (node:net:1407:8)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'EADDRINUSE',
  errno: -4091,
  syscall: 'listen',
  address: '::',
  port: 443
}

Based on my progress so far, I think the issue is with me creating more "dining space" instead of hiring more "workers".

How do I properly create instances of a server with proper load balancing using clusters?

CodePudding user response:

Building on @krtee 's post:

The core problem here is that you're essentially trying to create multiple processes on the same port.

This is true, and you're really close to the node docs on this!

// essentially all this stuff 
var httpsServer = https.createServer(options, app);

httpsServer.listen(443);
var app = express();
...

 // needs to go in the `else` block of the worker initialization

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

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
  });
}
else
{
  // right bout here.
}

CodePudding user response:

The core problem here is that you're essentially trying to create multiple processes on the same port

CodePudding user response:

Clustering in nodejs, by its very definition is a group of processes that are all set up to process incoming connections the same. The master process uses an algorithm to rotate incoming connections among the various clustered processes so that each one gets a turn handling incoming connections. This is typically used when you need to increase the number of CPUs that you use for processing incoming http requests. By default a single nodejs process runs your Javascript in only a single thread/CPU.

And, by definition, these clustered processes are all doing the same thing (handling incoming http requests) as you are doing in the main process.

If, what you really want is to run different code (lets say you were going to do some heavy duty image processing) and you rightly want to get that heavy CPU processing out of main thread so it can remain responsive to incoming connections, then you would use either a WorkerThread (more threads in the same process) or a child_process (more processes). In both of those cases, you can run whatever code you want in the WorkerThread or child_process and it can be completely different than what you're doing in your main nodejs program.

If the underlying issue is some processing you're doing in a POST handler on your web server, then whether or not you need to investigate any of the above ways to scale depends entirely upon what you're doing in that POST handler. Nodejs by itself, with its asynchronous I/O model (for networking, file I/O, database access, etc...) can handle a ton of simultaneous requests without involving additional threads or processes. Properly written asynchronous code scales really well in nodejs.

So, unless your process is heavily using the CPU (as in the image processsing example I used above), then you should just write good asynchronous code first, see how that works and perhaps load test it to find where your bottlenecks are. You may indeed find that your bottlenecks are insigificant (thus you can get scale quite high) or they are not in a place that would benefit from the above additional processes and you need to attack the specific causes of the bottlenecks. With any high scale design, you first implement the basics, then instrument at scale to understand your bottlenecks, measure again, work on the bottlenecks, measure again, etc...

Guessing where your bottlenecks are is usually very error prone which causes you to put software engineering into the wrong places. Don't guess. Test, measure, find bottlenecks, work on bottlenecks. Rinse, lather, repeat.

  • Related