Я получаю повторяющиеся сообщения в моем кластерном приложении node.js / socket.io / redis pub / sub - PullRequest
6 голосов
/ 03 декабря 2011

Я использую Node.js, Socket.io с Redisstore, Cluster от ребят из Socket.io и Redis.

У меня есть приложение pub / sub, которое хорошо работает только на одном узле Node.js. Но, когда он работает под большой нагрузкой, используется только одно ядро ​​сервера, поскольку Node.js не написан для многоядерных машин.

Как вы можете видеть ниже, я сейчас использую модуль Cluster от Learnboost, тех же людей, которые делают Socket.io.

Но когда я запускаю 4 рабочих процесса, каждый клиент браузера, который входит и подписывается, получает 4 копии каждого сообщения, опубликованного в Redis. Если есть три рабочих процесса, есть три копии.

Полагаю, мне нужно как-то переместить функциональность redis pub / sub в файл cluster.js.

Cluster.js

var cluster = require('./node_modules/cluster');

cluster('./app')
  .set('workers', 4)
  .use(cluster.logger('logs'))
  .use(cluster.stats())
  .use(cluster.pidfiles('pids'))
  .use(cluster.cli())
  .use(cluster.repl(8888))
  .listen(8000);

App.js

redis = require('redis'),
sys = require('sys');

var rc = redis.createClient();

var path = require('path')
  , connect = require('connect')
  , app = connect.createServer(connect.static(path.join(__dirname, '../')));

// require the new redis store
var sio = require('socket.io')
  , RedisStore = sio.RedisStore
  , io = sio.listen(app);

io.set('store', new RedisStore);io.sockets.on('connection', function(socket) {
    sys.log('ShowControl -- Socket connected: ' + socket.id);

    socket.on('channel', function(ch) {
        socket.join(ch)
        sys.log('ShowControl -- ' + socket.id + ' joined channel: ' + ch);
    });

    socket.on('disconnect', function() {
        console.log('ShowControll -- Socket disconnected: ' + socket.id);
    });
});

rc.psubscribe('showcontrol_*');

rc.on('pmessage', function(pat, ch, msg) {
    io.sockets.in(ch).emit('show_event', msg);
    sys.log('ShowControl -- Publish sent to channel: ' + ch);
});

// cluster compatiblity
if (!module.parent) {
  app.listen(process.argv[2] || 8081);
  console.log('Listening on ', app.address());
} else {
  module.exports = app;
}

client.html

<script src="http://localhost:8000/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script>
    var socket = io.connect('localhost:8000');
    socket.emit('channel', 'showcontrol_106');
    socket.on('show_event', function (msg) {
        console.log(msg);
        $("body").append('<br/>' + msg);
    });
</script>

Ответы [ 2 ]

3 голосов
/ 08 декабря 2011

Оказывается, что это не проблема с Node.js / Socket.io, я просто делал это совершенно неправильно.

Мало того, что я публиковал на сервере Redis снаружи Node/ Стек сокетов, у меня все еще была прямая подписка на канал Redis.На обоих концах ситуации pub / sub я обошел стороной «кластер Socket.io с Redis Store на заднем конце».

Итак, я создал небольшое приложение (с Node.js / Socket.io / Express), которое брало сообщения из моего приложения Rails и «объявляло» их в комнату Socket.io с помощью socket.io-announceмодуль.Теперь, используя магию маршрутизации Socket.io, каждый рабочий узла будет получать и отправлять сообщения только в подключенные к ним браузеры.Другими словами, больше нет повторяющихся сообщений, так как и pub, и sub произошли в стеке Node.js / Socket.io.

После того, как мой код будет очищен, я помещу пример на github,

3 голосов
/ 03 декабря 2011

Я боролся с cluster и socket.io.Каждый раз, когда я использую функцию кластера (хотя я использую встроенный кластер Nodejs), я сталкиваюсь с множеством проблем с производительностью и проблемами с socket.io.

Пытаясь исследовать это, я копался в отчетах об ошибках и подобных сообщениях на socket.io git, и у всех, кто использует кластеры или внешние балансировщики нагрузки на своих серверах, возникают проблемы с socket.io.

Похоже, возникает проблема «клиент не должен быть согласован, клиент должен переподключиться», которую вы увидите, если увеличите подробное ведение журнала.Это появляется много раз, когда socket.io работает в кластере, поэтому я думаю, что это возвращается к этому.IE клиент подключается к рандомизированному экземпляру в кластере socket.io каждый раз, когда он устанавливает новое соединение (он выполняет несколько соединений http / socket / flash при авторизации и еще больше - при опросе новых данных).

На данный момент я вернулся к использованию только одного процесса socket.io одновременно, это может быть ошибкой, но также может быть недостатком того, как создается socket.io.

Добавлено: Мой путьРешением этой проблемы в будущем будет назначение уникального порта каждому экземпляру socket.io внутри кластера, а затем выбор порта для кэширования на стороне клиента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...