版权声明:欢迎转载 https://blog.csdn.net/qq924862077/article/details/84797525
在之前的一篇博客《RocketMQ原理学习--消息类型》中我们有介绍过RocketMQ的消息类型,这篇博客我们简单介绍一下RocketMQ消费者是如何消费消息的。
一、Pull or Push
简单来说RocketMQ给我们提供了两种消息消费方式,Pull模式和Push模式,简单理解我们可能会认为Pull模式是消费者主动去拉取消息,Push模式是RocketMQ的Broker主动将消息推送过来,其实RocketMQ对于这两种方式都是采用的Pull拉取的方式,Push模式不过是通过回调来实现的,让我们理解为推送模式
1、Push示例:
提供一个MessageListenerConcurrently监听器,当存在消息时会回调这个类的consumeMessage方法。
public class PushConsumer {
public static void main(String[] args) throws InterruptedException, MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("rmq-group");
consumer.setNamesrvAddr("localhost:9876");
//consumer.setInstanceName("rmq-instance2");
consumer.subscribe("TopicA-test", "TagA");
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(
List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()));
}
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
});
consumer.start();
System.out.println("Consumer Started.");
}
2、Pull模式:
维护MessageQueue和消息offset不断的去拉取消息。
public class PullConsumer {
private static final Map<MessageQueue, Long> OFFSE_TABLE = new HashMap<>();
public static void main(String [] args) throws Exception{
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("rmq-group");
consumer.start();
Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("TopicA-test");
for (MessageQueue mq : mqs) {
System.out.printf("Consume from the queue: %s%n", mq);
SINGLE_MQ:
while (true) {
try {
PullResult pullResult =
consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32);
System.out.printf("%s%n", pullResult);
putMessageQueueOffset(mq, pullResult.getNextBeginOffset());
switch (pullResult.getPullStatus()) {
case FOUND:
break;
case NO_MATCHED_MSG:
break;
case NO_NEW_MSG:
break SINGLE_MQ;
case OFFSET_ILLEGAL:
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
consumer.shutdown();
}
private static long getMessageQueueOffset(MessageQueue mq) {
Long offset = OFFSE_TABLE.get(mq);
if (offset != null)
return offset;
return 0;
}
private static void putMessageQueueOffset(MessageQueue mq, long offset) {
OFFSE_TABLE.put(mq, offset);
}
}
二、执行流程
1、Push模式:
对于Push模式,RocketMQ提供了PullMessageService线程,定时不断的从RocketMQ中拉取消息,最终来回调MessageListener的consumeMessage方法来消费消息,如下执行流程图: