这里写目录标题
推模式
代码上使用 DefaultMQPushConsumer
这种模型下,系统收到消息后自动调用处理函数来处理消息,自动保存 Offset,并且加入新的消费者后会自动做负载均衡。
底层实现上,推模式还是使用的 pull 来实现的,pull 就是拉取,push 方式是 Server 端接收到消息后,主动把消息推给 Client 端,实时性高。但是使用 Push 方式有很多弊端,首先加大 Server 端的工作量,其次不同的 Client 端处理能力不同,Client 的状态不受 Server 控制,如果 Client 不能及时处理 Server 推送过来的消息,会造成各种潜在问题。
所以 RocketMQ 是通过“长轮询”的方式,同时通过 Client 端和 Server 端的配合,达到既拥有 Pull 的优点,又能达到确保实时性的目的。
集群
使用相同 Group ID 的订阅者属于同一个集群。同一个集群下的订阅者消费逻辑必须完全一致(包括 Tag 的使用),这些订阅者在逻辑上可 以认为是一个消费节点。
集群消费
当使用集群消费模式时,消息队列 RocketMQ 认为任意一条消息只需要被集群内的任意一个消费者处理即可。
1.创建消费者PushConsumerA,PushConsumerB,PushConsumerC,内部代码完全一样,消费同一个群组group1
package org.example.normal;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
/**
* 消费者-推模式
**/
public class PushConsumerA {
public static void main(String[] args) throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");
consumer.subscribe("TopicA", "*");
consumer.setNamesrvAddr("192.168.42.112:9876");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);//每次从最后一次消费的偏移量开始消费
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
System.out.println("queueID:"+list.get(0).getQueueId());
System.out.println("ThreadName:"+Thread.currentThread().getName());
System.out.println("Messages:" + new String(list.get(0).getBody()));
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.println("ConsumerPartOrder Started.");
}
}
2.启动3个消费者
3.使用单向发送生产10条消息
4.查看打印,一个queue只能被一个消费者消费
PushConsumerA
ConsumerPartOrder Started.
queueID:3
ThreadName:ConsumeMessageThread_4
Messages:Hello RocketMQ3
queueID:3
ThreadName:ConsumeMessageThread_5
Messages:Hello RocketMQ7
PushConsumerB
ConsumerPartOrder Started.
queueID:0
ThreadName:ConsumeMessageThread_1
Messages:Hello RocketMQ0
queueID:1
ThreadName:ConsumeMessageThread_2
Messages:Hello RocketMQ1
queueID:0
ThreadName:ConsumeMessageThread_3
Messages:Hello RocketMQ4
queueID:0
ThreadName:ConsumeMessageThread_4
Messages:Hello RocketMQ8
queueID:1
ThreadName:ConsumeMessageThread_5
Messages:Hello RocketMQ5
queueID:1
ThreadName:ConsumeMessageThread_6
Messages:Hello RocketMQ9
PushConsumerC
ConsumerPartOrder Started.
queueID:2
ThreadName:ConsumeMessageThread_1
Messages:Hello RocketMQ2
queueID:2
ThreadName:ConsumeMessageThread_2
Messages:Hello RocketMQ6
广播消费
当使用广播消费模式时,消息队列 RocketMQ 会将每条消息推送给集群内所有注册过的客户端,保证消息至少被每台机器消费一次。
5.创建消费者BroadConsumerA,BroadConsumerB,BroadConsumerC,代码完全一样,设置消费模式为广播模式
package org.example.broadcast;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import java.util.List;
/**
* 消费者-广播消费
**/
public class BroadConsumerA {
public static void main(String[] args) throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");
consumer.subscribe("TopicA", "*");
consumer.setNamesrvAddr("192.168.42.112:9876");
consumer.setMessageModel(MessageModel.BROADCASTING);//设置消费模式为广播模式
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);//每次从最后一次消费的偏移量开始消费
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
System.out.println("queueID:"+list.get(0).getQueueId()+",ThreadName:"+Thread.currentThread().getName()
+",Messages:" + new String(list.get(0).getBody()));
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.println("ConsumerPartOrder Started.");
}
}