kafka消费者和异步处理程序

时间:2018-08-13 13:12:53

标签: node.js apache-kafka kafka-consumer-api

我有一个带有Kafka订阅者的node.js应用。 订阅处理程序使用“ fetch”来调用远程REST API(等待fetch(...))。

我尝试处理大量消息,由于远程服务器超载,REST调用失败。

发生过载是因为订阅者进程是异步的。

我的问题是: 有没有办法确保异步处理程序已序列化,因此不会同时调用远程API服务器?

克里斯: 我正在使用kafka-node

这是一个代码示例:

const consumer = new Consumer(this.client, [{ topic: topicKey}]);
consumer.on('message', function (message) {
  handleMessage(message)
});

async function handleMessage(message) {
   ... decode the message

  // Send to the Remote server using a REST call

  //=> the task is suspended, waiting for the IO, so, meantime, the next message
  //   is processed, and I flood the remote server of POST requests.
  await fetch(...);
}

谢谢。

2 个答案:

答案 0 :(得分:2)

我不确定您想要实现什么。我了解您的API过载,因为您同时进行了太多调用。

因此,如果我的理解很好,则希望同步进行。

正如我在评论中所说,我认为队列是一个不错的选择。这就是我的方法(您可能会找到在其他地方实现队列的更好方法,但是我只是给您一个想法:D)

const consumer = new Consumer(this.client, [{ topic: topicKey}]);
const myQueue = [];

consumer.on('message', function (message) {
    myQueue.push(message);
});

async function consumeQueue(){
    const message = myQueue.shift();

    if(!message){
        await sleep(3000);
    } else {
        // ... decode your message
        await fetch(message)
    }

    consumeQueue();
}

function sleep(ms){
    return new Promise(resolve => setTimeout(resolve, ms));
}

// you have to init it :D
consumeQueue();

答案 1 :(得分:0)

如果您只想暂停“流”,直到执行异步代码。由于可读流(ConsumerGroupStream)可以暂停并再次恢复,因此以下方法可以很好地工作。

    const kafka = require('kafka-node')

    const options = {
      kafkaHost: '127.0.0.1:9092',
      groupId: 'Group'
    };

    const consumerGroupStream = new kafka.ConsumerGroupStream(options, ['queue']);

    consumerGroupStream
      .on('data', (massage) => {
        consumerGroupStream.pause();
        console.log('Message: ', massage, Date.now());
        asyncFunction().then(() => {
          console.log('Now data will start flowing again.', Date.now());
          consumerGroupStream.resume();
        });
      });

第二个选项是使用转换流 https://nodejs.org/api/stream.html#stream_class_stream_transform

    const kafka = require('kafka-node')

    const options = {
      kafkaHost: '127.0.0.1:9092',
      groupId: 'Group'
    };

    const consumerGroupStream = new kafka.ConsumerGroupStream(options, ['queue']);

    async function asyncFunction(message) {
      console.log('Message: ', message);
    }

    const Transform = require('stream').Transform

    const messageTransform = new Transform({
      objectMode: true,
      decodeStrings: true,
      transform (message, encoding, done) {
        asyncFunction(message).then(() => {
          done()
        })
      }
    })

    consumerGroupStream
      .pipe(messageTransform)