在Heroku上使用cluster和socket.io-redis缩放node.js socket.io@1.*.*

有没有人知道一个很好的解决scheme来扩展一个基于node.js – socket.io的应用程序在多个核心? 我目前正在testingsocket.io文档中提供的解决scheme,以在多个节点上使用socket.io,但没有取得具体的成功。

我在github上创build了一个操作系统: https : //github.com/liviuignat/socket.io-clusters ,它是从socket.io站点修改的聊天应用程序的一个拷贝。 它使用expressclustersocket.io@1.1.0socket.io-redis

目前还有一个在分支feature/sticky使用sticky-session的实现,似乎更好。

最后,这个应用程序需要发布到Heroku ,并扩展到多个dynos。

最初我尝试做这样的事情 – 只为群集节点启动服务器,但我总是得到错误: 失败:连接closures之前收到握手响应

 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(); } 

然后,我尝试启动服务器也为主节点:

 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(); } 

我也尝试过在分支feature/sticky同时使用sticky-sessionsocket.io-redis ,这似乎是成功执行的,但似乎仍然不是一个好的解决scheme:

 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'); }); } 

我会在接下来的日子里做更多的testing,但如果有人能提出一些想法,这将会有很大的帮助。

谢谢,

你可能正在寻找socket.io-redis。 http://socket.io/blog/introducing-socket-io-1-0/ (滚动至“Scalability”)

下面是关于如何使用socket.io + express创build脚手架的简短示例:

 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有pub / sub,所有的socket.io节点都需要订阅redis来获取来自某个频道的所有消息。 通过这种方式,一个进程可以将一条消息广播到一个通道(发布),而所有其他进程以最小的延迟接收这些消息,以将它们广播到他们连接的客户端(订阅)。 你甚至可以用基于redis的会话来扩展它。

在我看来,你所指的集群模块有点误导。 就我所了解的概念而言,它有助于创build永久的子stream程,但不会在多个节点之间“同步”渠道。 如果你的客户不需要与他人沟通就没有问题。 如果您想在所有节点上向所有连接的客户端广播消息,则需要使用redis模块。