使用Redis Pub / Sub

时间:2019-04-08 14:31:21

标签: node.js redis socket.io

因此,首先,我构建了一个微服务,该足球可获取Football API,并通过redis的pub / sub系统发布,如果存在生命周期更改,它将发布所有更改。

现在,我的服务器(带有套接字和路由)将处于群集模式。我已经使用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 :(得分:0)

可能有多种解决方案可以解决,例如:

使用消息队列而不是pub / sub

根据处理的数量,您可能只希望一个节点来处理消息。在这种情况下,发布/订阅不是您想要的。例如,您可以将消息存储在列表中,然后使用LPOP命令来获取和删除消息。然后,您可以说“第一个抓住了它”-这样,只有一台服务器可以完成工作,但是基本上是一个随机服务器。 您还可以使用不同的消息队列,例如RabbitMQ,SQS等。

使用socket.io-emitter发送消息

由于无论如何都使用socket.io-redis,因此消息将分发到节点。有一个项目属于socket.io-redis的一部分,称为socket.io-emitter。那可以用来向您的所有节点发送消息,而不必成为一个节点。当您在工作程序微服务中实现该功能时(目前将消息写到“ livescore”的服务),您可以将消息直接发送给客户。 但是,如果您需要在节点应用程序中处理消息,则可能不起作用。