0

I am working on a NodeJS & RabbitMQ where -

  • A Master NodeJS Service (one instance) Pushes the data in a queue.
  • Slave NodeJS Services (multiple instances) consume the data and process it.
  • Default exchange is being used.

The slave service is running in PM2 Cluster Mode, which means I have got 8 instances for the slave service running.

My expectation was, as the master service starts pushing in data through the queue, The slave services should start consuming them asynchronously.

As an example, if master service is pushing 10 jobs through the queue and if each job is taking 5 seconds to complete, it takes slaves 50 seconds to finish the job.

This is completely defeating the purpose of using multiple slaves as I would nomaly want slaves to pick up 8 jobs at a time.

As per the RabbitMQ dashboard, above setup creates -

  • 9 connections ( 1 master + 8 slaves )
  • 9 channels (1 master + 8 slaves )
  • 1 queue

The whole setup uses default exchange.

My question is -

Why are the slaves not able to read data from the queue asynchronously?

Even is I set noAck to true the next item in the queue will not get picked up until curent item is processed

My intention is to scale up the queue consumption rate by user multiple slave instances but I think I am missing something here.

Here's the codebase -

const rabbitMq = require("amqplib");

class RabbitMQClient {

    async connect() {
        this.connection = await rabbitMq.connect("amqp://admin:password@localhost");
        this.channel = await this.connection.createChannel();
        await this.channel.assertQueue("TEST_QUEUE");
    }
}


// MASTER CODE (This Runs In Fork Mode - 1 Instance)
const master_client = new RabbitMQClient();
master_client.connect().then(() => {
    // sending in 10 messages
    for (let index = 1; index <= 10; index++) {
        const data = Buffer.from(index.toString(), "utf8");
        master_client.channel.sendToQueue("TEST_QUEUE", data);
    }
});


// SLAVE CODE (This Runs In Cluster Mode - 8 Instances)
const slave_client = new RabbitMQClient();
// connect to rabbitmq
slave_client.connect().then(() => {
    // consume the messages
    slave_client.channel.consume("TEST_QUEUE", (data) => {
        // timeout to add delay
        setTimeout(() => {
            RabbitMQClient._channel.ack(data);
        }, 5000);
    });
});

The slave output -

33|slave | 2020-11-02 13:19:09.293 +00:00: recieved message - 1  (13-19-09)
34|slave | 2020-11-02 13:19:14.293 +00:00: recieved message - 2  (13-19-14)
35|slave | 2020-11-02 13:19:19.299 +00:00: recieved message - 3  (13-19-19)
36|slave | 2020-11-02 13:19:24.299 +00:00: recieved message - 4  (13-19-24)
37|slave | 2020-11-02 13:19:29.300 +00:00: recieved message - 5  (13-19-29)
38|slave | 2020-11-02 13:19:34.299 +00:00: recieved message - 6  (13-19-34)
39|slave | 2020-11-02 13:19:39.301 +00:00: recieved message - 7  (13-19-39)
40|slave | 2020-11-02 13:19:44.301 +00:00: recieved message - 8  (13-19-44)
33|slave | 2020-11-02 13:19:49.299 +00:00: recieved message - 9  (13-19-49)
34|slave | 2020-11-02 13:19:54.300 +00:00: recieved message - 10 (13-19-54)

If you notice, different slaves are picking up the messages in round-robin fashion but they are working synchronously.

Thanks!

planet_hunter
  • 3,866
  • 1
  • 26
  • 39

1 Answers1

0

Queues are single threaded in RabbitMQ, which can not dispatch messages in parallel at the same time. But this does not mean that consumers are not processing at the same time. When the one consumer is consuming, other consumers bound to the same queue can receive the message at the same time and start consumption.

How to increase throughput

In general, the following tips always be helpful:

  • Split your queues over different cores. You can use RabbitMQ Sharding plugin, which can automatically shard the queue, or you can do it manually
  • Set a optimal prefetch count for each consumer, which can reduce network cost of consumers to obtain messages
  • 1 channel per consumer. Same as queue, channel is also single threaded

For more detail, you can visit here

spike 王建
  • 1,556
  • 5
  • 14