【问题标题】:Some problems when scaling Socket.IO to multiple Node.js processes using cluster使用集群将 Socket.IO 扩展到多个 Node.js 进程时的一些问题
【发布时间】: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();
      }
    }

【问题讨论】:

标签: javascript node.js socket.io


【解决方案1】:

默认情况下,socket.io 会连接多个连续的 http 请求。它基本上以 HTTP 轮询模式开始,然后在一些初始数据交换之后,它切换到 webSocket 传输。

因此,没有任何类型的粘性负载平衡的集群将无法工作。每个初始连续的 http 请求都应该发送到同一个服务器进程,很可能会被发送到集群中的不同服务器进程,初始连接将无法正常工作。

我知道有两种解决方案:

  1. 实现某种粘性负载平衡(在集群模块中),以便每个客户端重复地转到同一个服务器进程,因此在连接开始时所有连续的 http 请求都将转到同一个服务器进程.

  2. 切换您的客户端配置以立即切换到 webSocket 传输,并且从不使用 HTTP 轮询。连接仍会以 http 请求开始(因为所有 webSocket 连接都是这样开始的),但完全相同的连接将升级为 webSocket,因此永远只有一个连接。

仅供参考,您还需要确保 socket.io 中的重新连接逻辑正确地重新连接到所连接的原始服务器进程。

socket.io 结合 redis 支持 node.js 集群。虽然 socket.io 文档站点已经关闭了好几天,但您可以找到一些信息 hereScaling Socket.IO to multiple Node.js processes using cluster 以及这里的 previously cached version of the socket.io doc for clustering

【讨论】:

  • 真的很有帮助!谢谢!
猜你喜欢
  • 2013-08-21
  • 2014-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多