我在群集的node.js / socket.io / redis pub / sub应用程序中收到重复消息

我正在使用Node.js,Redisstore的Socket.io,Socket.io家伙的Cluster和Redis。

我有一个发布/订阅应用程序,只有一个Node.js节点运行良好。 但是,当负载过重时,由于Node.js不是为多核机器编写的,因此最多只能是服务器的一个核心。

正如你在下面看到的,我现在使用了来自Learnboost的Cluster模块,和使用Socket.io的人一样。

但是,当启动4个工作进程时,每个进入和订阅的浏览器客户端都会获得Redis中发布的每条消息的4个副本。 如果有三个工作进程,则有三个副本。

我猜我需要将redis pub / subfunction以某种方式移动到cluster.js文件。

Cluster.js

var cluster = require('./node_modules/cluster'); cluster('./app') .set('workers', 4) .use(cluster.logger('logs')) .use(cluster.stats()) .use(cluster.pidfiles('pids')) .use(cluster.cli()) .use(cluster.repl(8888)) .listen(8000); 

App.js

 redis = require('redis'), sys = require('sys'); var rc = redis.createClient(); var path = require('path') , connect = require('connect') , app = connect.createServer(connect.static(path.join(__dirname, '../'))); // require the new redis store var sio = require('socket.io') , RedisStore = sio.RedisStore , io = sio.listen(app); io.set('store', new RedisStore);io.sockets.on('connection', function(socket) { sys.log('ShowControl -- Socket connected: ' + socket.id); socket.on('channel', function(ch) { socket.join(ch) sys.log('ShowControl -- ' + socket.id + ' joined channel: ' + ch); }); socket.on('disconnect', function() { console.log('ShowControll -- Socket disconnected: ' + socket.id); }); }); rc.psubscribe('showcontrol_*'); rc.on('pmessage', function(pat, ch, msg) { io.sockets.in(ch).emit('show_event', msg); sys.log('ShowControl -- Publish sent to channel: ' + ch); }); // cluster compatiblity if (!module.parent) { app.listen(process.argv[2] || 8081); console.log('Listening on ', app.address()); } else { module.exports = app; } 

client.html

 <script src="http://localhost:8000/socket.io/socket.io.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script> <script> var socket = io.connect('localhost:8000'); socket.emit('channel', 'showcontrol_106'); socket.on('show_event', function (msg) { console.log(msg); $("body").append('<br/>' + msg); }); </script> 

我一直在与群集和socket.io战斗。 每次我使用集群function(我使用内置的Nodejs集群,虽然),我得到了很多的性能问题和socket.io的问题。

在试图研究这个问题的时候,我一直在深入研究socket.io git上的错误报告和类似的问题,任何使用集群或者外部负载均衡器的人在他们的服务器上似乎都遇到了socket.io的问题。

它似乎产生的问题“客户端不握手客户端应该重新连接”,你会看到如果你增加详细日志logging。 每当socket.io在群集中运行时,都会出现很多,所以我认为它会回到这个状态。 IE浏览器客户端每次连接到socket.io集群中的随机实例时,它会进行一次新的连接(授权时会连接多个http /套接字/闪存连接,以后会在查询新数据时进行更多操作)。

现在我已经恢复到只使用一个socket.io进程,这可能是一个错误,但也可能是如何构buildsocket.io的一个缺点。

补充:我今后解决这个问题的方法是为集群内的每个socket.io实例分配一个唯一的端口,然后在客户端caching端口select。

事实certificate,这不是Node.js / Socket.io的问题,我只是用完全错误的方式来解决这个问题。

我不仅从Node / Socket栈之外发布到Redis服务器,还直接订阅了Redis频道。 在pub / sub的两端,我绕过了“后端有Redis Store的Socket.io集群”的好处。

所以,我创build了一个小应用程序(使用Node.js / Socket.io / Express),它从我的Rails应用程序中获取消息,并使用socket.io-announce模块将它们“宣布”到Socket.io房间中。 现在,通过使用Socket.io路由魔法,每个节点工作人员只会直接获取并发送消息给与之连接的浏览器。 换句话说,由于pub和sub都发生在Node.js / Socket.io栈中,所以没有更多的重复消息。

在我清理完代码之后,我会在某个地方给github上个例子。