消息队列全文
消息属性
生产
- 消息生产组,对于普通消息意义不大;用于配合事务的回查机制
DefaultMQProducer producer = new DefaultMQProducer("group_test");
- 设置每一个主题在每一个Broker队列数量,默认4个,创建时有效
producer.setDefaultTopicQueueNums(8);
- 发送消息的默认超时时间,默认3s
producer.setSendMsgTimeout(1000 * 4);
- 消息超过阈值,启动压缩,默认4k
producer.setCompressMsgBodyOverHowmuch(1024 * 4);
- 同步发送失败的重试次数,默认2次
producer.setRetryTimesWhenSendFailed(2);
- 异步发送失败的重试次数,默认2次
producer.setRetryTimesWhenSendAsyncFailed(2);
- 消息重试时选择另一个Broker发送,默认为false
producer.setRetryAnotherBrokerWhenNotStoreOK(true);
- 允许发送的最大信息长度,默认4M
producer.setMaxMessageSize(1024 * 1024 * 4);
- 设置nameserver的地址
producer.setNamesrvAddr("127.0.0.1:9876");
消费
- 指定消费者组,集群消费组,每一个组均摊消费同一个主题的消息
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("sqlFilter");
- 消费模式,默认就是集群
consumer.setMessageModel(MessageModel.CLUSTERING);
- 指定消费开始的偏移量,上次消费偏移量/最大偏移量/最小偏移量/启动时间戳
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
- 消费者最小偏移数量,默认20
consumer.setConsumeThreadMin(20);
- 消费者最大偏移数量,默认20
consumer.setConsumeThreadMax(20);
- 推模式的任务间隔,推模式是一种不断轮询调取的封装
consumer.setPullInterval(0);
- 推模式下任务拉取一批的条数,默认32条
consumer.setPullBatchSize(32);
- 消息重试次数,-1代表16,超过代表死信消息
consumer.setMaxReconsumeTimes(-1);
- 消息消费超时时间,阻塞当前线程的最大时间,分钟为单位
consumer.setConsumeTimeout(15);
- 消费者的主题下有多少消息队列
Set<MessageQueue> queues = consumer.fetchSubscribeMessageQueues("Topic");
普通消息
- maven依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.8.0</version>
</dependency>
消息发送
同步消息发送
DefaultMQProducer producer = new DefaultMQProducer("group_test");
// 设置nameserver的地址
producer.setNamesrvAddr("127.0.0.1:9876");
//启动producer
producer.start();
for (int i = 0; i < 10; i++) {
Message msg = new Message("TopicTest",
"TagA",
("hello rocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult result = producer.send(msg);
System.out.println(result);
}
// 即时关闭
producer.shutdown();
异步发送
DefaultMQProducer producer = new DefaultMQProducer("group_test");
// 设置nameserver的地址
producer.setNamesrvAddr("127.0.0.1:9876");
//启动producer
producer.start();
for (int i = 0; i < 10; i++) {
Message msg = new Message("TopicTest",
"TagB",
("hello rocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
// 传入异步回调接口
producer.send(msg, new SendCallback() {
// 发送成功
@Override
public void onSuccess(SendResult sendResult) {
System.out.println(sendResult);
}
// 发送失败
@Override
public void onException(Throwable throwable) {
throwable.printStackTrace();
}
});
}
Thread.sleep(10000);
// 即时关闭
producer.shutdown();
单向发送
DefaultMQProducer producer = new DefaultMQProducer("group_test");
// 设置nameserver的地址
producer.setNamesrvAddr("127.0.0.1:9876");
//启动producer
producer.start();
for (int i = 0; i < 10; i++) {
Message msg = new Message("TopicTest",
"TagC",
("hello rocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
// 得不到响应结果
producer.sendOneway(msg);
}
// 即时关闭
producer.shutdown();
消息消费
- 集群消费,一个消费组,均摊消费一个topic的消息
- 消息不回重复
- 消费进度保存在broker
- 广播消费,一个消费组中每一个消费者,会将所有消息都消费一遍
- 消息重复,不支持顺序消息,重置消费点
- 消费进度,保存在消费者
- 只会处理消费者启动时获取的最新消息
集群消费
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group_consumer");
// 指定注册中心
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅Topic 指定tag
consumer.subscribe("TopicTest", "TagC");
// 集群模式消费,默认就是集群
consumer.setMessageModel(MessageModel.CLUSTERING);
// 注册回调处理函数
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
try {
for (MessageExt msg : list) {
String topic = msg.getTopic();
String msgBody = new String(msg.getBody(), "utf-8");
String tags = msg.getTags();
System.out.println("topic: " + topic + " body: " + msgBody + " tags: " + tags);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
// 关闭
//consumer.shutdown();
广播消费
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group_consumer");
// 指定注册中心
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅Topic 指定tag
consumer.subscribe("TopicTest", "TagB");
// 区别就是消费模式
consumer.setMessageModel(MessageModel.BROADCASTING);
// 注册回调处理函数
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
try {
for (MessageExt msg : list) {
String topic = msg.getTopic();
String msgBody = new String(msg.getBody(), "utf-8");
String tags = msg.getTags();
System.out.println("topic: " + topic + " body: " + msgBody + " tags: " + tags);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
// 关闭
//consumer.shutdown();
顺序消息
生产
全局顺序消息
- 先进先出,发送消息的时候,指定队列
SendResult result = producer.send(msg, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
return list.get((Integer) o);
}
}, 1);
部分顺序消息
- 不同的msg放入不同的queue,发送时,实现
MessageQueueSelector
接口
DefaultMQProducer producer = new DefaultMQProducer("group_test");
// 设置nameserver的地址
producer.setNamesrvAddr("172.20.10.12:9876");
//启动producer
producer.start();
List<Integer> orders = new ArrayList<>();
for (int i = 0; i < 10; i++) {
orders.add(i);
}
for (int i = 0; i < orders.size(); i++) {
Message msg = new Message("OrderTest",
"TagA",
("order " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult result = producer.send(msg, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
return list.get((Integer) o % list.size());
}
}, i);
System.out.println(result.getMessageQueue().getQueueId() + " - " + i);
}
// 即时关闭
producer.shutdown();
不同Queue的消费
- 顺序消费要实现
MessageListenerOrderly
接口,并且异常返回等一会在处理,否则会影响顺序
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group_consumer");
// 指定注册中心
consumer.setNamesrvAddr("127.0.0.1:9876");
// 消费的起始偏移
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
// 订阅Topic 指定tag
consumer.subscribe("OrderTest", "*");
// 注册回调处理函数
consumer.registerMessageListener(new MessageListenerOrderly() {
Random r = new Random();
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
consumeOrderlyContext.setAutoCommit(true);
for (MessageExt msg : list) {
System.out.println("consumerThread " + Thread.currentThread().getName() +
" queueId " + msg.getQueueId() + " content " + new String(msg.getBody()));
}
try {
TimeUnit.MILLISECONDS.sleep(r.nextInt(300));
} catch (InterruptedException e) {
e.printStackTrace();
// 如果顺序消息的处理,不能返回重试,要等一会,在进行处理
// 重试会影响顺序
return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
consumer.start();
延时消息
- 延迟一段时间再发给消费者
- 限时订单,没有及时支付的订单,释放掉
生产
DefaultMQProducer producer = new DefaultMQProducer("group_test");
// 设置nameserver的地址
producer.setNamesrvAddr("127.0.0.1:9876");
//启动producer
producer.start();
for (int i = 0; i < 10; i++) {
Message msg = new Message("ScheduledTopic", ("Hello scheduled message " + i).getBytes(StandardCharsets.UTF_8));
// 18个等级 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
msg.setDelayTimeLevel(2);
producer.send(msg);
}
producer.shutdown();
消费
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group_consumer");
// 指定注册中心
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅Topic 指定tag
consumer.subscribe("ScheduledTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt msg : list) {
System.out.println("msgId: " + msg.getMsgId() + " time: " +
(msg.getStoreTimestamp() - msg.getBornTimestamp()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
批量消息
- 一批消息大小不能超过4m,大的批量消息需要进行拆分
普通生产
DefaultMQProducer producer = new DefaultMQProducer("group_test");
// 设置nameserver的地址
producer.setNamesrvAddr("127.0.0.1:9876");
//启动producer
producer.start();
List<Message> msgs = new ArrayList<>();
for (int i = 0; i < 10; i++) {
msgs.add(new Message("BatchTopic", "TagD", i + "", ("Hello " + i).getBytes(StandardCharsets.UTF_8)));
}
producer.send(msgs);
producer.shutdown();
消费
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group_consumer");
// 指定注册中心
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅Topic 指定tag
consumer.subscribe("BatchTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt msg : list) {
System.out.println("msgId: " + msg.getMsgId() + " content: " +
new String(msg.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
过滤消息
- Tag过滤,支持正则表达式
消费者订阅时,指定tag即可
- SQL过滤
broker
要配置enablePropertyFilter=true
生产
DefaultMQProducer producer = new DefaultMQProducer("group_test");
// 设置nameserver的地址
producer.setNamesrvAddr("127.0.0.1:9876");
//启动producer
producer.start();
String[] tags = new String[]{"TagA", "TagB", "TagC"};
for (int i = 0; i < 10; i++) {
Message msg = new Message("SQLFilterTopic", tags[i % 3],
("Hello " + i).getBytes(StandardCharsets.UTF_8));
msg.putUserProperty("a", String.valueOf(i));
SendResult res = producer.send(msg);
System.out.println(res);
}
producer.shutdown();
消费
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("sqlFilter");
// 指定注册中心
consumer.setNamesrvAddr("127.0.0.1:9876");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
// 订阅Topic 指定tag
consumer.subscribe("SQLFilterTopic",
MessageSelector.bySql("TAGS is not null and TAGS in ('TagA', 'TagB') and" +
"(a is not null and a between 0 and 3)"));
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt msg : list) {
String topic = msg.getTopic();
String body = new String(msg.getBody());
String pro = msg.getProperty("a");
String tags = msg.getTags();
System.out.println("topic: " + topic +
"\nbody: " + body +
"\npro: " + pro +
"\ntags: " + tags);
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();