我的node.js服务器使用群集模块来处理多个进程。
如果服务器通过Socket.IO接收来自客户端的请求,它会使用redis发布将数据传送到另一台服务器。它通过redis订阅接收精确数据,然后只是将这些数据丢给客户端。
我使用一个节点进程来接收带有redis sub的数据,以及使用socket.io将数据发送到客户端的其他进程。
当页面加载时,客户端连接socket.io。 这是我的问题。 连接事件反复发生,甚至连页面都没有加载。 当客户端连接时,我从该套接字获取socket.id,稍后当我想将数据发送到该客户端套接字时,我会使用它。但这种连接反复发生,我认为客户端使用的socket已经改变了。所以,我记得的第一个socket.id将毫无用处。我无法从该socket.id发送数据。我将auth信息存储在套接字对象中,因此更改的客户端套接字没有帮助。
index.pug
$(document).ready(function(){
var socket = io.connect();
(...)
app.js
var cluster = require('cluster');
var socketio = require('socket.io');
var NRP = require('node-redis-pubsub');
var nrpForChat = new NRP(config.chatRedisConfig);
var nrpForCluster = new NRP(config.clusterRedisConfig);
var startExpressServer = function(){
var app = express();
var server = require('http').createServer(app);
var io = socketio.listen(server);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6380 }));
io.sockets.on('connection', function(socket){
socketController.onConnect(io, socket, nrpForChat);
});
server.listen(config.port, function(){
console.log('Server app listening on port '+config.port);
});
nrpForCluster.on('to:others:proc', function(data){
var socket = io.sockets.connected[data.target.sockid];
if (socket) {
if (data.event == '_net_auth') {
if (data.data.res){
socket.enterId = data.data.data.enterId;
socket.memberKey = data.data.data.memberKey;
socket.sid = data.data.data.sid;
socket.emit(data.event, data.data);
}else{
console.log('auth failed.');
}
}
} else {
socket.emit(data.event, data.data);
}
});
module.exports = app;
}
var numCpus = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCpus; i++) {
cluster.fork();
}
}
else {
if (cluster.worker.id == numCpus) {
nrpForChat.on('chat:to:relay', function(data){
nrpForCluster.emit('to:others:proc', data);
});
if (numCpus == 1) {
startExpressServer();
}
}
else {
startExpressServer();
}
}
答案 0 :(得分:4)
默认情况下,socket.io连接多个连续的http请求。它基本上以HTTP轮询模式启动,然后在一些初始数据交换之后,它切换到webSocket传输。
因此,没有任何粘性负载平衡的群集将无法正常工作。所有应该转到同一服务器进程的每个初始连续http请求可能会被发送到集群中的不同服务器进程,并且初始连接将不起作用。
我知道有两种解决方案:
实现某种粘性负载平衡(在群集模块中),以便每个客户端重复进入同一服务器进程,因此连接开始时所有连续的http请求将转到同一服务器进程
切换客户端配置以立即切换到webSocket传输,从不使用HTTP轮询。连接仍将以http请求开始(因为这就是所有webSocket连接的启动方式),但完全相同的连接将升级到webSocket,因此只会有一个连接。
仅供参考,您还需要确保socket.io中的重新连接逻辑正确地重新连接到已连接的原始服务器进程。
socket.io与redis结合使用node.js群集支持。虽然socket.io文档网站已经停用了好几天,但您可以找到一些信息here和Scaling Socket.IO to multiple Node.js processes using cluster,这里是previously cached version of the socket.io doc for clustering。