Scale node.js socket.io@1. *. * With cluster and socket.io-redis on Heroku

Does anyone know a good solution for scaling a node.js application - socket.io on multiple cores? I am currently testing the solution presented in the socket.io documentation for using socket.io on multiple nodes, but without concrete success.

I created a playing field for this on github: https://github.com/liviuignat/socket.io-clusters , which is a slightly modified copy of the chat application from socket.io. It uses express , cluster , socket.io@1.1.0 and socket.io-redis .

Currently, there is also an implementation using sticky-session in the feature/sticky branch, which seems to work better.

In the end, the application should be published in Heroku , scaled to multiple speakers.

Initially, I tried to do something like this - to start the server only for cluster nodes, but I always get an error: failed: the connection is closed before receiving a handshake response

 if (cluster.isMaster) { for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log('worker ' + worker.process.pid + ' died'); }); } else { var server = new Server({ dirName: __dirname, enableSocket: true }) .setupApp() .setupRoutes() .start(); } 

Then I tried to start the server also for the master nodes:

 if (cluster.isMaster) { var server = new Server({ dirName: __dirname, enableSocket: true }) .setupApp() .setupRoutes() .start(); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log('worker ' + worker.process.pid + ' died'); }); } else { var server = new Server({ dirName: __dirname, enableSocket: true }) .setupApp() .setupRoutes() .start(); } 

I also tried this using both sticky-session and socket.io-redis in the feature/sticky branch, which seems to work with success, but still is not a good solution:

 if (cluster.isMaster) { sticky(function() { var server = new Server({ dirName: __dirname, enableSocket: true }) .setupApp() .setupRoutes(); return server.http; }).listen(3000, function() { console.log('server started on 3000 port'); }); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function(worker, code, signal) { console.log('worker ' + worker.process.pid + ' died'); }); } else { sticky(function() { var server = new Server({ dirName: __dirname, enableSocket: true }) .setupApp() .setupRoutes(); return server.http; }).listen(3000, function() { console.log('server started on 3000 port'); }); } 

I will be doing more tests in the coming days, but it would help a lot if someone could come up with some ideas.

Thanks,

+6
source share
1 answer

You may be looking for socket.io-redis. http://socket.io/blog/introducing-socket-io-1-0/ (go to "Scalability")

Here's a shortened example of how to create forests using socket.io + express:

 var cluster = require('cluster'); var express = require('express') , app = express() , server = require('http').createServer(app); var io = require('socket.io').listen(server) var redis = require('socket.io-redis'); io.adapter(redis({ host: 'localhost', port: 6379 })); var workers = process.env.WORKERS || require('os').cpus().length; /** * Start cluster. */ if (cluster.isMaster) { /** * Fork process. */ console.log('start cluster with %s workers', workers-1); workers--; for (var i = 0; i < workers; ++i) { var worker = cluster.fork(); console.log('worker %s started.', worker.process.pid); } /** * Restart process. */ cluster.on('death', function(worker) { console.log('worker %s died. restart...', worker.process.pid); cluster.fork(); }); } else { server.listen(process.env.PORT || 9010); } 

Redis has pub / sub, and all socket.io nodes must subscribe to redis in order to receive all messages from the channel. Thus, one process can broadcast a message to a channel (publish), and all other processes receive messages with a minimum delay for their transmission to connected clients (subscription). You can even extend this with redis sessions.

The cluster module you are referencing is a bit misleading in my opinion. This helps to create invisible subprocesses, as far as I understand the concept, but does not "synchronize" channels through several nodes. If your customers do not need to communicate with others, this is great. If you want to send messages to all connected clients on all nodes, you need a redis module.

+2
source

Source: https://habr.com/ru/post/976061/


All Articles