优化RabbitMQ消费者以批量消费

时间:2018-12-16 08:55:47

标签: node.js rabbitmq amqp node-amqp node-amqplib

我有一个应用程序,在该应用程序上,每消耗一条消息,我都需要查询MySQL数据库以获取一些信息,并基于该过程处理消耗的消息。我想对此进行优化,以防止对数据库的多个查询加起来。

我正在考虑一种方法,等待至少 x条消息 y秒。这样,我可以批量使用一些消息,即使在某个时候收到的消息较少,它们也将被使用。

示例:假设 x = 100 y = 10秒

这意味着我等待至少100条消息或10秒,以先到者为准。这样,我可以一次在数据库中查询100条消息。另外,如果我收到的消息少于100条,则剩余的消息将在最多10秒的时间内处理。

我正在使用NodeJS和amqplib进行消费。我有以下基于RabbitMQ示例的代码:

amqp.connect('amqp://localhost', function(err, conn) {
  conn.createChannel(function(err, ch) {
    var q = 'hello';

    ch.assertQueue(q, {durable: false});
    console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", q);
    ch.consume(q, function(msg) {
      console.log(" [x] Received %s", msg.content.toString());
    }, {noAck: true});
  });
});

我当时正在考虑有一个全局对象,并在每个consume回调中添加一个全局对象,并在到达 x条消息时检查该对象的计数。不过,不确定如何为此添加上限时间 y秒,并确保如果我在时间窗口内收到的消息少于 x条消息,则这些消息将得到处理< / p>

1 个答案:

答案 0 :(得分:0)

以下代码将在每条收到的消息之后调用一个函数,该函数将收到的消息聚合到一个数组中。在没有消息的情况下调用它(带有参数null)或看到消息数已达到x时,它将聚合的消息发送到数据库函数。否则,它只是将消息添加到数组中(在if语句的第二部分中)。

参数null由计时器传递给聚合函数,该计时器在y秒后触发。当消息队列刚刚初始化时,将首先设置此计时器,并在聚合器将消息发送到数据库中时重置此计时器。

var messageStore = [];
var timer;

sendToDatabase = function(messages) {...}

aggregate = function(msg) {
    if (msg == null || messageStore.push(msg) == x) {
        clearTimeout(timer);
        timer = setTimeout(aggregate, 1000*y, null);
        sendToDatabase(messageStore);
        messageStore = [];
    }
}

amqp.connect('amqp://localhost', function(err, conn) {
  conn.createChannel(function(err, ch) {
    var q = 'hello';

    ch.assertQueue(q, {durable: false});
    console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", q);
    timer = setTimeout(aggregate, 1000*y, null);
    ch.consume(q, function(msg) {
      console.log(" [x] Received %s", msg.content.toString());
      aggregate(msg);
    }, {noAck: true});
  });
});

注意:由于手头没有消息传递系统,因此我无法对其进行测试。