Рукопожатие WebSocket в Node.JS, Socket.IO и кластерах не работает

У меня возникла проблема с кластеризацией моего приложения с кластерами Node.js, socket.io и node.js.

Я использовал socket.io-redis, чтобы поделиться информацией для всех работников, но не работает.

Мой код:

var cluster   = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {   
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {      
    cluster.fork();
  }

  cluster.on('exit', function(worker, code, signal) {
    console.log('worker ' + worker.process.pid + ' died');
  });
} else {

    ...

         var express   = require("express");
         //Server
         var server = express();
         //Socket.io
         var http  = require('http').Server(server);
         var io    = require('socket.io')(http);
         var redis_io = require('socket.io-redis'); 
         var redis = require("redis");

         io.adapter(redis_io({host: "127.0.0.1", port: 6379 })); 

    ...
}

В клиенте я получаю ошибки при рукопожатии, такие как ошибка 400 или WebSocket закрывается до установления соединения.

Что я могу сделать, чтобы решить это?

Я использую последнюю версию node.js и socket.io

Спасибо!

1 ответ

У меня была такая же проблема, и мне потребовалось некоторое время, чтобы понять это. Небольшое исследование объяснило, что это происходит потому, что некоторым транспортам, таким как длинный опрос, нужно сделать несколько запросов, чтобы установить оптимальное соединение. Между запросами сохраняется состояние, поэтому, если разные последовательные запросы направляются разным работникам кластера, соединение не устанавливается.

Об этом есть страница по адресу http://socket.io/docs/using-multiple-nodes/ где приводятся пользовательские cluster модуль называется sticky-session который работает вокруг этого: https://github.com/indutny/sticky-session

Я действительно не хотел использовать его, так как это в основном игнорирует всю работу, которую команда node.js вкладывает в балансировку нагрузки TCP за модулем кластера.

Поскольку самому протоколу Web Socket требуется только одно соединение, я смог обойти это, заставив websocket быть первым и единственным транспортом. Я могу сделать это, потому что я контролирую клиента и сервера. Для общедоступной веб-страницы это может быть небезопасно, поскольку вам нужно беспокоиться о совместимости браузера. В моем случае клиент - мобильное приложение.

Вот код клиента JavaScript, который я вставил на свою тестовую страницу (опять же, настоящий клиент - это мобильное приложение, поэтому моя веб-страница на самом деле просто помогает в создании и тестировании):

var socket = io('http://localhost:8080/', {
  transports: [ 'websocket' ]
});

Вы должны использовать липкий сеанс, чтобы клиенты не подключались к разным серверам во время первоначального рукопожатия. Обратитесь к этому https://github.com/elad/node-cluster-socket.io

Другие вопросы по тегам