我正在使用Node.js,带有Redisstore的Socket.io,来自Socket.io的集群以及Redis。
我有一个发布/订阅应用程序,仅在一个Node.js节点上运行良好。但是,当它承受沉重的负担时,它最多只能耗尽服务器的一个核心,因为Node.js并不是为多核计算机编写的。
如您在下面看到的,我现在使用的是Learnboost的Cluster模块,这是制造Socket.io的人。
但是,当我启动4个工作进程时,进入并订阅的每个浏览器客户端都会获得Redis中发布的每个消息的4个副本。如果有三个工作进程,则有三个副本。
我猜我需要以某种方式将redis pub / sub功能移动到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>
原来这不是Node.js / Socket.io的问题,我只是用完全错误的方式来解决它。
我不仅从Node / Socket堆栈外部发布到Redis服务器,而且仍然直接订阅Redis频道。在发布/订阅情况的两端,我都绕过了“后端带有Redis存储的Socket.io群集”的优点。
因此,我创建了一个小应用程序(使用Node.js / Socket.io / Express),该应用程序从Rails应用程序中接收消息,并使用socket.io- announce模块将其“宣布”到Socket.io房间中。现在,通过使用Socket.io路由魔术,每个节点工作人员将仅获取消息并将消息发送到直接与其连接的浏览器。换句话说,由于pub和sub都发生在Node.js / Socket.io堆栈中,因此不再有重复的消息。
清理代码后,我将在github上的地方放一个示例。