#node.js #redis #socket.io
#node.js #redis #socket.io
Вопрос:
Итак, во-первых, я создал микросервис, который извлекает Football API, и через pub / sub систему 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;
Итак, если я запускаю единственный экземпляр этого приложения node, все работает отлично.
Но если я запускаю его в режиме кластера, допустим, есть 4 кластера (я запускаю режим кластера с pm2), произойдет следующее:
- Микросервис публикует событие.
- У каждого кластера есть подписка на канал «прямая трансляция»
- Каждый кластер выполняет io.emit() (для всех клиентов)
- Клиент получает 4 одинаковых события практически в одно и то же время.
Я понял, почему клиент получает 4 одинаковых события, но я хочу знать, как правильно с этим справиться?
Моя единственная мысль о решении заключается в том, что я делаю redis sub только в одном кластере и публикую все из него, но я боюсь, что это было бы слишком большой работой для одного кластера?
Есть идеи?
Комментарии:
1. вы нашли его решение?
2. есть какие-либо обновления по поиску решения?
Ответ №1:
Вероятно, существует несколько решений для исправления этого, вы могли бы, например:
Используйте очередь сообщений вместо pub / sub
В зависимости от количества операций обработки, вы, вероятно, хотите, чтобы сообщение обрабатывал только один узел. Pub / sub — это не то, что вам нужно в этом случае. Вы могли бы, например, сохранить свои сообщения в списке и использовать команду LPOP для получения и удаления сообщения. Тогда вы могли бы сказать, что «первый поймает это» — таким образом, только один из ваших серверов будет выполнять работу, но в основном случайный. Вы также могли бы использовать отдельную очередь сообщений, такую как RabbitMQ, SQS и т.д.
Используйте socket.io-emitter для отправки сообщений
Поскольку вы в любом случае используете socket.io-redis, ваши сообщения будут распределены по вашим узлам. Есть проект, который является частью socket.io-redis, он называется socket.io-emitter. Которые можно использовать для отправки сообщений на все ваши узлы, не являясь таковыми сами по себе. Когда вы реализуете это в своем рабочем микросервисе (том, который в данный момент записывает сообщение в «live»), вы можете отправлять сообщения напрямую своим клиентам. Однако это может не сработать, если вам нужно обрабатывать сообщения в вашем приложении node.