1

I am creating a Node.js application for collaborative drawing on an HTML5 canvas. I am using Socket.IO to communicate and I have implemented clustering so I am able to scale my application. My lecturer told me that using clustering is a good idea, but it would not be smart to make every core in the cpu do the same thing, i.e. that defeats the purpose. So in my case it would not be smart to have 8 cores working on the exact same painting, but instead maybe have 8 different paintings, one painting for each core. I also know that Socket.IO only communicates through one core. Right now I am a bit confused on where and how to start. I know that there is this "sticky" socket.io module, but that would just share communication but not make a different painting for each core?

Here is the server I have made:

let http = require('http').Server(application);
let socketIO = require('socket.io')(http);
let cluster = require('cluster'); 
let cores= require('os').cpus().length;

if (cluster.isMaster) {
    for (let i = 0; i < cores; i++) {
        cluster.fork();
    }

} else {
    process.exit();
}

function connect(socket){
    socket.on('test',
        function emit(data) {
            socket.broadcast.emit('test', data);
        });
}

socketIO.on('connection', connect);

http.listen(port);
  • What do we expect the CPU to do in this context? They are not doing any drawing correct?, they are only responsible from serving sockets / so the coordinates / colors could be transferred? – Mavi Domates Dec 12 '18 at 11:21
  • Yes correct, I only emit colors and coordinates –  Dec 12 '18 at 11:25
  • Well the way that I see it, your CPUs will be doing the same thing (socket.io work) anyways. I think splitting tasks would have made more sense if you had some background agents / worker roles to do something different. – Mavi Domates Dec 12 '18 at 11:31
  • I want them to do different paintings each :) –  Dec 12 '18 at 11:36
  • So that I wouldn't waste all 8 cores for one painting –  Dec 12 '18 at 11:38
  • And what if you only have 1 painting? – Mavi Domates Dec 12 '18 at 11:43
  • BTW - they would do different paintings, if you have 8 paintings which N people per drawing are drawing at the same, chances are your load distribution on the workers would be pretty even if you don't only use the master. – Mavi Domates Dec 12 '18 at 11:45
  • Isn't there a way to do it this way: If you exceed 10 clients, create a new painting on the second cpu core and so on, 20 clients, third core. I know it would be different paintings, so not everyone will see the same, that's fine –  Dec 12 '18 at 11:48

1 Answers1

0

I think your CPU cores will be doing something very similar anyways, but I believe this question should be re-worded in a way that it's exploring how would you solve this through utilizing multiple CPUs assuming you have >= X paintings where X is the # of CPUs. You don't directly assign CPU's to individual paintings, OS is well optimized to come up with smart ways of choosing the best available one.

See how the workers are setup to listen to socket connections? You can emit the data that you want to emit in each of the workers.

Code below is taken from this SO post, I've slightly changed it.

var cluster = require('cluster');
var os = require('os');

if (cluster.isMaster) {
  // we create a HTTP server, but we do not use listen
  // that way, we have a socket.io server that doesn't accept connections
  var server = require('http').createServer();
  var io = require('socket.io').listen(server);
  var redis = require('socket.io-redis');

  io.adapter(redis({ host: 'localhost', port: 6379 }));

  for (var i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }

  cluster.on('exit', function(worker, code, signal) {
    console.log('worker ' + worker.process.pid + ' died');
  }); 
}

if (cluster.isWorker) {
  var express = require('express');
  var app = express();

  var http = require('http');
  var server = http.createServer(app);
  var io = require('socket.io').listen(server);
  var redis = require('socket.io-redis');

  io.adapter(redis({ host: 'localhost', port: 6379 }));
  io.on('connection', function(socket) {
    // grandeFasola - emit what you what to emit here.
    socket.emit('data', 'connected to worker: ' + cluster.worker.id);
  });

  app.listen(80);
}
Mavi Domates
  • 4,262
  • 2
  • 26
  • 45
  • So just to understand correctly. The code above creates a server, but doesn't listen on it? If it's a worker, we create another server, so we end up with a server for each worker, and one for the master? –  Dec 12 '18 at 11:59
  • Yes - I think it's done that way for showing that you can separate the responsibilities. The workers would be listening on the same socket though, which should distribute the processing / emitting – Mavi Domates Dec 12 '18 at 12:02