使用集群将 Socket.IO 扩展到多个 Node.js 进程时的一些问题
Posted
技术标签:
【中文标题】使用集群将 Socket.IO 扩展到多个 Node.js 进程时的一些问题【英文标题】:Some problems when scaling Socket.IO to multiple Node.js processes using cluster 【发布时间】:2017-07-31 14:22:18 【问题描述】:我的 node.js 服务器使用集群模块来处理多个进程。
如果服务器使用 Socket.IO 接收来自客户端的请求,它会将数据传送到另一个使用 redis 发布的服务器。它通过 redis subscribe 接收精炼的数据,然后将这些数据扔给客户端。
我使用一个节点进程通过redis sub接收数据,其他进程通过socket.io向客户端发送数据。
当页面加载时客户端连接socket.io。 在这里,这是我的问题。 连接事件反复发生,甚至没有加载页面。 当客户端连接时,我从该套接字获取 socket.id,然后当我想向该客户端套接字发送数据时使用它。但是这种连接反复发生,我认为客户端使用的套接字发生了变化。所以,我记得的第一个 socket.id 是没用的。我无法从那个 socket.id 发送数据。我在socket对象中存储了auth信息,所以改变的客户端socket是没有用的。
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();
【问题讨论】:
看到这个link 【参考方案1】:默认情况下,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。
【讨论】:
真的很有帮助!谢谢!以上是关于使用集群将 Socket.IO 扩展到多个 Node.js 进程时的一些问题的主要内容,如果未能解决你的问题,请参考以下文章
在 Heroku 上使用集群和 socket.io-redis 扩展 node.js socket.io@1.*.*
在多核服务器中使用带有集群的 socket.io 的好方法?