我正在使用Node.js,Socket.io和Redisstore,来自Socket.io的人群和Redis。
我有一个pub / sub应用程序,它只适用于一个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>
答案 0 :(得分:3)
我一直在与cluster和socket.io进行斗争。每次我使用集群功能(我使用内置的Nodejs集群)我会遇到很多性能问题和socket.io的问题。
在尝试研究这个时,我一直在挖掘bug报告和类似的socket.io git,任何使用集群或外部负载平衡器到服务器的人似乎都有socket.io的问题。
它似乎产生了问题“客户端没有握手的客户端应该重新连接”,如果你增加详细的日志记录,你会看到它。每当socket.io在集群中运行时都会出现这种情况,所以我认为它会恢复到此状态。 I.E每次进行新的连接时,客户端都会连接到socket.io集群中的随机实例(它在授权时会进行多次http / socket / flash连接,并且在轮询新数据时会更多地进行连接)。
现在我已经恢复到一次只使用1个socket.io进程,这可能是一个错误,但也可能是socket.io的构建方式的缺点。
补充:我将来解决这个问题的方法是为集群内的每个socket.io实例分配一个唯一的端口,然后在客户端缓存端口选择。
答案 1 :(得分:3)
事实证明这不是Node.js / Socket.io的问题,我只是以完全错误的方式解决它。
我不仅从Node / Socket堆栈外部发布到Redis服务器,我还是直接订阅了Redis频道。在pub / sub情况的两端,我绕过了“后端Redis Store的Socket.io集群”的优点。
所以,我创建了一个小应用程序(带有Node.js / Socket.io / Express),它从我的Rails应用程序中获取消息,并使用socket.io-announce模块将它们“宣布”到Socket.io房间。现在,通过使用Socket.io路由魔术,每个节点工作者只能直接获取并向连接到它们的浏览器发送消息。换句话说,不再有重复的消息,因为pub和sub都发生在Node.js / Socket.io堆栈中。
在我清理完代码后,我会在某个地方的github上放一个例子。