【问题标题】:Socket IO Server Clusters working with Redis Pub/Sub使用 Redis Pub/Sub 的 Socket IO 服务器集群
【发布时间】:2019-04-08 14:31:20
【问题描述】:

首先,我构建了一个获取足球 API 的微服务,并通过 redis 的 pub/sub 系统,如果有任何变化,它会发布任何用于比分的变化。

现在我的服务器,带有套接字和路由,将处于集群模式。我已经用 socketio-redis 进行了设置。这是此设置的 sn-p:

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,并从该集群发布所有内容,但我担心这对一个集群来说工作量太大?

有什么想法吗?

【问题讨论】:

  • 你找到解决办法了吗?
  • 关于寻找解决方案的任何更新?

标签: node.js redis socket.io


【解决方案1】:

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

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

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

使用socket.io-emitter发送消息

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-19
    • 2018-08-16
    • 2017-10-25
    • 2011-08-05
    • 2012-12-01
    • 2019-12-02
    • 2015-11-09
    • 1970-01-01
    相关资源
    最近更新 更多