使用集群

时间:2017-03-10 09:39:53

标签: javascript node.js socket.io

我的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();
      }
    }

1 个答案:

答案 0 :(得分:4)

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

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

我知道有两种解决方案:

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

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

  3. 仅供参考,您还需要确保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