Серверные кластеры Socket IO, работающие с Redis Pub / Sub - PullRequest
0 голосов
/ 08 апреля 2019

Итак, во-первых, я создал микросервис, который загружает Football API, и через систему пабов / подсистем redis публикует любые изменения, если они есть, для livescores.

Теперь мой сервер с сокетами и маршрутами будет в кластерном режиме. Я уже настроил это с помощью socketio-redis. Вот фрагмент этой установки:

const io = require('socket.io')();
const sRedis = require('socket.io-redis');
const adapter = sRedis({ host: 'localhost', port: 6379 });
const { promisify } = require('util');
const Redis = require('ioredis');
const redis = new Redis();
redis.subscribe('livescore');



io.adapter(adapter);
const ioa = io.of('/').adapter;
ioa.clients = promisify(ioa.clients);
ioa.clientRooms = promisify(ioa.clientRooms);
ioa.remoteJoin = promisify(ioa.remoteJoin);
ioa.remoteLeave = promisify(ioa.remoteLeave);
ioa.allRooms = promisify(ioa.allRooms);

// notice this listener
redis.on('message', (channel, message) => {
    io.emit('livescore', message);
})


io.on('connect', async (socket) => {

    socket.clientRooms = () => ioa.clientRooms(socket.id);
    socket.remoteJoin = (room) => ioa.remoteJoin(socket.id, room);
    socket.remoteLeave = (room) => ioa.remoteLeave(socket.id, room);
    socket.remoteDisconnect = () => ioa.remoteDisconnect(socket.id);


    socket.on('join room', async (id) => {
        await socket.remoteJoin(id);
        socket.emit('join room', `You have joined room ${id}`)
        socket.broadcast.emit('join room', `${socket.id} has joined.`)
    });

    socket.on('leave room', (id) => {
        socket.remoteLeave(id);
    });


})

module.exports = io;

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

Но если я запускаю его в режиме кластера, скажем, есть 4 кластера (я использую режим кластера с pm2), происходит следующее:

  1. Микросервис публикует событие.
  2. Каждый кластер имеет подписку на канале «livescore»
  3. Каждый кластер выполняет io.emit () (для всех клиентов)
  4. Клиент получает 4 одинаковых события почти одновременно.

Я выяснил, почему клиент получает 4 одинаковых события, но я хочу знать, как правильно справиться с этим?

Моя единственная мысль о решении состоит в том, что я делаю redis sub только для одного кластера и публикую все из этого, но я боюсь, что это будет слишком много работы для одного кластера?

Есть идеи?

1 Ответ

0 голосов
/ 08 апреля 2019

Возможно, есть несколько решений, чтобы исправить это, например:

Использовать очередь сообщений вместо pub / sub

В зависимости от количества обработок, вы, вероятно, хотите, чтобы только один узел обрабатывал сообщение. Паб / саб не то, что вы хотите в этом случае. Например, вы можете сохранить свои сообщения в списке и использовать команду LPOP для получения и удаления сообщения. Тогда вы могли бы сказать, что «первый его поймает» - так будет работать только один из ваших серверов, но в основном случайный. Вы также можете использовать отдельную очередь сообщений, такую ​​как RabbitMQ, SQS и т. Д.

Используйте socket.io-emitter для отправки сообщений

Поскольку вы все равно используете socket.io-redis, ваши сообщения распределяются по вашим узлам. Есть проект, который является частью socket.io-redis, он называется socket.io-emitter . Это можно использовать для отправки сообщений на все ваши узлы, не будучи самим собой. Когда вы реализуете это в своем рабочем микросервисе (тот, который в данный момент пишет сообщение в «livescore»), вы можете отправлять сообщения напрямую своим клиентам. Это может не сработать, если вам нужно обрабатывать сообщения в вашем приложении узла.

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