Сбой авторизации Socket.io websocket при кластеризации узла приложения - PullRequest
2 голосов
/ 12 февраля 2012

Вопрос. Можно ли кластеризовать приложение, которое использует Socket.io для поддержки WebSocket? Если да, то какой метод реализации будет лучшим?

Я создал приложение, использующее Express и Socket.io, на основе Node.js. Я хотел бы включить кластеризацию, чтобы увеличить количество запросов, которые может обрабатывать мое приложение.

Следующее заставляет мое приложение выдавать ошибку установления связи сокета ...

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('death', function(worker) {
    console.log('worker ' + worker.pid + ' died');
  });
} else {
  app.listen(3000);  
}

Журнал консоли показывает, что socket.io запускается несколько раз.

jack@jack:~$ node nimble/app.js
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started

Socket.io в настоящее время настраивается в верхней части моего кода сервера, используя:

var io = require('socket.io').listen(app);

Код авторизации websocket:

//Auth the user
io.set('authorization', function (data, accept) {
  // check if there's a cookie header
  if (data.headers.cookie) {
    data.cookie = parseCookie(data.headers.cookie);
    data.sessionID = data.cookie['express.sid'];

    //Save the session store to the data object
    data.sessionStore = sessionStore;

    sessionStore.get(data.sessionID, function(err, session){
      if(err) throw err;

      if(!session)
      {
        console.error("Error whilst authorizing websocket handshake");
        accept('Error', false);
      }
      else
      {
        console.log("AUTH USERNAME: " + session.username);
        if(session.username){
          data.session = new Session(data, session);
          accept(null, true);
        }else {
          accept('Invalid User', false);
        }       

      }
    })
  } else {
    console.error("No cookie was found whilst authorizing websocket handshake");
    return accept('No cookie transmitted.', false);
  }
});

Консольный журнал сообщения об ошибке:

Error whilst authorizing websocket handshake
   debug - authorized
   warn  - handshake error Error

1 Ответ

2 голосов
/ 12 февраля 2012

Какой у тебя sessionStore?Если это MemoryStore, поставляемый с connect, то сеансы не будут разделены между вашими работниками.У каждого работника будет свой набор сеансов, и если клиент подключится к другому работнику, вы не найдете его сеанс.Я предлагаю вам взглянуть, например, connect-redis для совместного использования сеансов между процессами.Основное использование:

var connect = require('connect')
  , RedisStore = require('connect-redis')(connect);

var app = connect.createServer();
app.use(connect.session({store: new RedisStore, secret: 'top secret'});

Конечно, для этого также необходимо настроить redis.В Connect wiki есть модули для CouchDB, memcached, postgres и др.

Тем не менее, это решает только часть вашей проблемы, потому что теперь у вас есть сеансы, разделенные между работниками, но socket.io не имеет возможности отправлять сообщения клиентам, которые подключены к другим работникам.По сути, если вы введете socket.emit на одном работнике, это сообщение будет отправлено только клиентам, подключенным к тому же работнику.Одним из решений этой проблемы является использование RedisStore для socket.io, которое использует redis для маршрутизации сообщений между работниками.Основное использование:

var sio = require('socket.io')
  , RedisStore = sio.RedisStore
  , io = sio.listen(app);

io.set('store', new RedisStore);

Теперь все сообщения должны перенаправляться клиентам независимо от того, к какому работнику они подключены.

См. Также: Node.js, многопоточность иSocket.io

...