从单个REDIS实例读取Nodejs集群体系结构

时间:2019-05-18 12:08:37

标签: node.js redis cluster-computing

我正在使用Nodejs cluster模块来运行多个工作程序。 我创建了一个基本架构,其中将有一个MASTER进程,该进程基本上是一个处理多个请求的快速服务器,而MASTER的主要任务是将来自请求的传入数据写入REDIS实例。其他工作程序(numOfCPUs-1)将成为非主工作程序,即他们将不会处理任何请求,因为它们只是消费者。我有两个功能,即ABC和DEF。我通过为非主工作人员分配类型来平均分配他们。

例如:在8核计算机上:

1是通过快递服务器的MASTER实例处理请求

剩余(8-1 = 7)将平均分配。 4为特征:ABD,3为特征:DEF。

非主工人基本上是消费者,即他们从REDIS读取,只有主工人可以写入数据。

这是相同的代码:

if (cluster.isMaster) {
  // Fork workers.
  for (let i = 0; i < numCPUs - 1; i++) {
    ClusteringUtil.forkNewClusterWithAutoTypeBalancing();
  }

  cluster.on('exit', function(worker) {
    console.log(`Worker ${worker.process.pid}::type(${worker.type}) died`);
    ClusteringUtil.removeWorkerFromList(worker.type);
    ClusteringUtil.forkNewClusterWithAutoTypeBalancing();
  });

  // Start consuming on server-start
  ABCConsumer.start();
  DEFConsumer.start();

  console.log(`Master running with process-id: ${process.pid}`);
} else {
  console.log('CLUSTER  type', cluster.worker.process.env.type, 'running on', process.pid);
  if (
    cluster.worker.process.env &&
    cluster.worker.process.env.type &&
    cluster.worker.process.env.type === ServerTypeEnum.EXPRESS
  ) {
    // worker for handling requests
    app.use(express.json());
    ...
  }
{

除消费者从REDIS读取内容外,其他所有内容均正常运行。 由于特定功能有多个使用者,因此每个人都读取同一条消息并单独开始处理,这是我不想要的。如果有4个消费者,则1个被标记为忙碌,直到有空才能消费,有3个可用。一旦由MASTER将有关特定功能的消息写入REDIS,问题就出在该功能的所有3个可用使用者上。这意味着对于单个消息,将根据可用使用者的数量完成工作。

const stringifedData = JSON.stringify(req.body);
  const key = uuidv1();

  const asyncHsetRes = await asyncHset(type, key, stringifedData);

  if (asyncHsetRes) {
    await asyncRpush(FeatureKeyEnum.REDIS.ABC_MESSAGE_QUEUE, key);
    res.send({ status: 'success', message: 'Added to processing queue' });
  } else {
    res.send({ error: 'failure', message: 'Something went wrong in adding to queue' });
  }

消费者仅接受消息并在忙碌时停止

module.exports.startHeartbeat = startHeartbeat = async function(config = {}) {
  if (!config || !config.type || !config.listKey) {
    return;
  }

  heartbeatIntervalObj[config.type] = setInterval(async () => {
    await asyncLindex(config.listKey, -1).then(async res => {
      if (res) {
        await getFreeWorkerAndDoJob(res, config);
        stopHeartbeat(config);
      }
    });
  }, HEARTBEAT_INTERVAL);
};

理想情况下,该特定功能的一个使用者只能阅读一条消息。消费后,它被标记为忙碌,因此直到有空(我已经处理了),它才进一步消耗。下一条消息只能由其他可用消费者中的一个消费者处理。

请帮助我解决这个问题。同样,我希望只有一位免费消费者才能阅读一条消息,其余的免费消费者应该等待新消息。

谢谢

1 个答案:

答案 0 :(得分:1)

我不确定我是否完全了解您的Redis消费者体系结构,但是我觉得它与Redis本身的用例相矛盾。您想要实现的本质上是基于队列的消息传递,并且能够在消息完成后立即提交。

Redis具有其自己的pub / sub功能,但是它是基于即发即弃原则构建的。它不能区分使用者,它只是将数据发送给所有使用者,并假设其逻辑是处理传入数据。

我建议您使用RabbitMQ之类的队列服务器。您可以通过AMQP 0-9-1支持的某些功能来实现您的目标:消息确认,使用者的预取计数等。您可以使用非常敏捷的配置(例如 ok)设置集群,我想拥有X个使用者,每个使用者一次可以处理1条唯一的(!)消息,只有让服务器(rabbitmq)才会收到新消息)知道他们已经成功完成了邮件处理。这是高度可配置的且健壮的。

但是,如果您希望通过一些完全托管的服务而变得无服务器,以免调配虚拟机或其他任何东西来运行您选择的消息队列服务器,则可以使用AWS SQS。它具有非常相似的API和功能列表。

希望有帮助!