1.新建开发环境
新建一个maven工程,在pom.xml文件中加入如下依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>RocketMQ_Demo</artifactId>
<groupId>com.kebo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rocketmq_demo</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies>
</project>
2.思想分析
2.1生产者
1.创建消息生产者producer,并制定生产者组名
2.指定Nameserver地址
3.启动producer
4.创建消息对象,指定主题Topic、Tag和消息体
5.发送消息
6.关闭生产者producer
2.2消费者
1.创建消费者Consumer,制定消费者组名
2.指定Nameserver地址
3.订阅主题Topic和Tag
4.设置回调函数,处理消息
5.启动消费者consumer
3.基本样例
3.1发送消息
3.1.1发送同步消息
这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
package com.kebo.base.producer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import java.util.concurrent.TimeUnit;
/**
* @description: 发送同步消息
* @author: kb
* @create: 2021-01-24 20:54
**/
public class SyncProducer {
public static void main(String[] args) {
// 1.创建消息生产者producer,并制定生产者组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("defaultGroup");
// 2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3.启动producer
try {
defaultMQProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
// 4.创建消息对象,指定主题Topic、Tag和消息体
for (int i = 0; i < 10; i++) {
Message message = new Message();
message.setTopic("base");
message.setTags("baseTag");
message.setBody(("Hello World"+i).getBytes());
// 5.发送消息
try {
SendResult result = defaultMQProducer.send(message);
SendStatus sendStatus = result.getSendStatus();
String msgId = result.getMsgId();
int queueId = result.getMessageQueue().getQueueId();
System.out.println(sendStatus);
System.out.println(msgId);
System.out.println(queueId);
} catch (Exception e) {
e.printStackTrace();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 6.关闭生产者producer
defaultMQProducer.shutdown();
}
}
3.1.2发送异步消息
异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
package com.kebo.base.producer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.util.concurrent.TimeUnit;
/**
* @description: 发送异步消息
* @author: kb
* @create: 2021-01-24 22:11
**/
public class AsyncProducer {
public static void main(String[] args) {
// 1.创建消息生产者producer,并制定生产者组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("defaultGroup");
// 2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3.启动producer
try {
defaultMQProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
// 4.创建消息对象,指定主题Topic、Tag和消息体
for (int i = 0; i < 10; i++) {
Message message = new Message();
message.setTopic("base");
message.setTags("asyncTag");
message.setBody(("Hello World" + i).getBytes());
// 5.发送异步消息
try {
defaultMQProducer.send(message, new SendCallback() {
/**
* @Description: 发送成功的回调函数
* @Param: [sendResult]
* @return: void
* @Author: kb
* @Date: 2021/1/24
* @Time: 22:13
*/
public void onSuccess(SendResult sendResult) {
System.out.println("发送成功"+sendResult);
}
/**
* @Description: 发送失败的回调函数
* @Param: [throwable]
* @return: void
* @Author: kb
* @Date: 2021/1/24
* @Time: 22:14
*/
public void onException(Throwable throwable) {
System.out.println("发送异常"+throwable);
}
});
} catch (Exception e) {
e.printStackTrace();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 6.关闭生产者producer
defaultMQProducer.shutdown();
}
}
3.1.3发送单向消息
这种方式主要用在不特别关心发送结果的场景,例如日志发送。
package com.kebo.base.producer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import java.util.concurrent.TimeUnit;
/**
* @description: 发送单向消息
* @author: kb
* @create: 2021-01-25 18:44
**/
public class OneWayProducer {
public static void main(String[] args) {
// 1.创建消息生产者producer,并制定生产者组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("defaultGroup");
// 2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3.启动producer
try {
defaultMQProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
// 4.创建消息对象,指定主题Topic、Tag和消息体
for (int i = 0; i < 10; i++) {
Message message = new Message();
message.setTopic("base");
message.setTags("oneWayTag");
message.setBody(("Hello World" + i).getBytes());
// 5.发送消息
try {
//发送单向消息
defaultMQProducer.sendOneway(message);
} catch (Exception e) {
e.printStackTrace();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 6.关闭生产者producer
defaultMQProducer.shutdown();
}
}
3.2消费消息
package com.kebo.base.consumer;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
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.message.MessageExt;
import java.util.List;
/**
* @description: 消息接收者
* @author: kb
* @create: 2021-01-25 19:09
**/
public class Consumer {
public static void main(String[] args) {
// 1. 创建消费者Consumer,制定消费者组名
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer("defaultGroup");
// 2. 指定Nameserver地址
defaultMQPushConsumer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3. 订阅主题Topic和Tag
try {
defaultMQPushConsumer.subscribe("base", "baseTag");
// 4. 设置回调函数,处理消息
defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
//接受消息内容
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (int i = 0; i <list.size() ; i++) {
System.out.println(new String(list.get(i).getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
} catch (MQClientException e) {
e.printStackTrace();
}
// 5. 启动消费者consumer
try {
defaultMQPushConsumer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
}
}
消费消息有两种模式,一种是负载均衡模式,另一种是广播模式,可以通过代码修改
//设置消费模式为广播模式,默认为负载均衡
defaultMQPushConsumer.setMessageModel(MessageModel.BROADCASTING);
3.3顺序消息
消息有序指的是可以按照消息的发送顺序来消费(FIFO)。RocketMQ可以严格的保证消息有序,可以分为分区有序或者全局有序。
顺序消费的原理解析,在默认的情况下消息发送会采取Round Robin轮询方式把消息发送到不同的queue(分区队列);而消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序。当发送和消费参与的queue只有一个,则是全局有序;如果多个queue参与,则为分区有序,即相对每个queue,消息都是有序的。
下面用订单进行分区有序的示例。一个订单的顺序流程是:创建、付款、推送、完成。订单号相同的消息会被先后发送到同一个队列中,消费时,同一个OrderId获取到的肯定是同一个队列。
package com.kebo.order;
import java.util.ArrayList;
import java.util.List;
/**
* @description:
* @author: kb
* @create: 2021-01-25 19:43
**/
public class OrderStep {
private long orderId;
private String describe;
public long getOrderId() {
return orderId;
}
public void setOrderId(long orderId) {
this.orderId = orderId;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
@Override
public String toString() {
return "OrderStep{" +
"orderId=" + orderId +
", describe='" + describe + '\'' +
'}';
}
public static List<OrderStep> buildOrders() {
List<OrderStep> orderStepList = new ArrayList<OrderStep>();
OrderStep orderDemo01 = new OrderStep();
orderDemo01.setOrderId(1039L);
orderDemo01.setDescribe("创建");
orderStepList.add(orderDemo01);
OrderStep orderDemo02 = new OrderStep();
orderDemo02.setOrderId(1065L);
orderDemo02.setDescribe("创建");
orderStepList.add(orderDemo02);
OrderStep orderDemo03 = new OrderStep();
orderDemo03.setOrderId(7235L);
orderDemo03.setDescribe("创建");
orderStepList.add(orderDemo03);
OrderStep orderDemo04 = new OrderStep();
orderDemo04.setDescribe("完成");
orderDemo04.setOrderId(1039L);
orderStepList.add(orderDemo04);
OrderStep orderDemo05 = new OrderStep();
orderDemo05.setOrderId(1065L);
orderDemo05.setDescribe("完成");
orderStepList.add(orderDemo05);
OrderStep orderDemo06 = new OrderStep();
orderDemo06.setOrderId(7235L);
orderDemo06.setDescribe("完成");
orderStepList.add(orderDemo06);
return orderStepList;
}
}
package com.kebo.order;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: kb
* @create: 2021-01-25 19:50
**/
public class Producer {
public static void main(String[] args) {
// 1.创建消息生产者producer,并制定生产者组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("defaultGroup");
// 2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3.启动producer
try {
defaultMQProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
// 4.创建消息对象,指定主题Topic、Tag和消息体
List<OrderStep> orderStepList = OrderStep.buildOrders();
for (int i = 0; i < orderStepList.size(); i++) {
Message message = new Message();
message.setTopic("base");
message.setTags("baseTag");
//message.setKeys("i+" + i);
message.setBody(orderStepList.get(i).toString().getBytes());
// 5.发送消息
try {
/*
参数一:消息对象
参数二:消息队列的选择器
参数三:选择队列的业务标识 (订单ID)
*/
SendResult result = defaultMQProducer.send(message, new MessageQueueSelector() {
/**
* @Description:
* @Param: [list消息队列, message消息对象, 业务表示的参数]
* @return: org.apache.rocketmq.common.message.MessageQueue
* @Author: kb
* @Date: 2021/1/25
* @Time: 19:58
*/
public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
long orderId = Long.valueOf(String.valueOf(o)).longValue();
long index = orderId % list.size();
return list.get((int) index);
}
}, orderStepList.get(i).getOrderId());
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 6.关闭生产者producer
defaultMQProducer.shutdown();
}
}
package com.kebo.order;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.*;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: kb
* @create: 2021-01-25 20:10
**/
public class Consumer {
public static void main(String[] args) {
// 1. 创建消费者Consumer,制定消费者组名
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer("defaultGroup");
// 2. 指定Nameserver地址
defaultMQPushConsumer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3. 订阅主题Topic和Tag
try {
defaultMQPushConsumer.subscribe("base", "baseTag");
// 4. 设置回调函数,处理消息
defaultMQPushConsumer.registerMessageListener(new MessageListenerOrderly() {
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
for (int i = 0; i < list.size(); i++) {
System.out.println(Thread.currentThread().getName()+"->"+new String(list.get(i).getBody()));
}
/*try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
return ConsumeOrderlyStatus.SUCCESS;
}
});
} catch (MQClientException e) {
e.printStackTrace();
}
// 5. 启动消费者consumer
try {
defaultMQPushConsumer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
}
}
3.4延迟消息
比如电商里,提交了一个订单就可以发送一个延时消息,1h后去检查这个订单的状态,如果还是未付款就取消订单释放库存。
现在RocketMq并不支持任意时间的延时,需要设置几个固定的延时等级,从1s到2h分别对应着等级1到18
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
package com.kebo.delay;
import com.kebo.order.OrderStep;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: kb
* @create: 2021-01-25 21:15
**/
public class Producer {
public static void main(String[] args) throws Exception {
// 1.创建消息生产者producer,并制定生产者组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("defaultGroup");
// 2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3.启动producer
try {
defaultMQProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
// 4.创建消息对象,指定主题Topic、Tag和消息体
List<OrderStep> orderStepList = OrderStep.buildOrders();
for (int i = 0; i < orderStepList.size(); i++) {
Message message = new Message();
message.setTopic("delayBase");
message.setTags("baseTag");
message.setBody(orderStepList.get(i).toString().getBytes());
//设定延迟时间
message.setDelayTimeLevel(3);
// 5.发送消息
SendResult result = defaultMQProducer.send(message);
System.out.println(result);
}
TimeUnit.SECONDS.sleep(1);
// 6.关闭生产者producer
defaultMQProducer.shutdown();
}
}
package com.kebo.delay;
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.common.message.MessageExt;
import java.util.List;
/**
* @description:
* @author: kb
* @create: 2021-01-25 21:15
**/
public class Consumer {
public static void main(String[] args) throws Exception {
// 实例化消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("defaultGroup");
// 2.指定Nameserver地址
consumer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 订阅Topics
consumer.subscribe("delayBase", "baseTag");
// 注册消息监听者
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messages, ConsumeConcurrentlyContext context) {
for (MessageExt message : messages) {
System.out.println("Receive message[msgId=" + message.getMsgId() + "] " + (System.currentTimeMillis() - message.getBornTimestamp()) + "ms later");
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 启动消费者
consumer.start();
}
}
3.5批量消息
批量发送消息能显著提高传递小消息的性能。限制是这些批量消息应该有相同的topic,相同的waitStoreMsgOK,而且不能是延时消息。此外,这一批消息的总大小不应超过4MB。
package com.kebo.batch;
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.message.MessageExt;
import java.util.List;
/**
* @description: 消息接收者
* @author: kb
* @create: 2021-01-25 19:09
**/
public class Consumer {
public static void main(String[] args) throws Exception {
// 1. 创建消费者Consumer,制定消费者组名
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer("defaultGroup");
// 2. 指定Nameserver地址
defaultMQPushConsumer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3. 订阅主题Topic和Tag
defaultMQPushConsumer.subscribe("base", "Tag1");
// 4. 设置回调函数,处理消息
defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
//接受消息内容
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (int i = 0; i < list.size(); i++) {
System.out.println(new String(list.get(i).getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 5. 启动消费者consumer
defaultMQPushConsumer.start();
}
}
package com.kebo.batch;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @description: 发送批量消息
* @author: kb
* @create: 2021-01-24 20:54
**/
public class SyncProducer {
public static void main(String[] args) throws Exception {
// 1.创建消息生产者producer,并制定生产者组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("defaultGroup");
// 2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3.启动producer
defaultMQProducer.start();
List<Message> messageList = new ArrayList<Message>();
// 4.创建消息对象,指定主题Topic、Tag和消息体
Message message1 = new Message("base","Tag1",("Hello World"+1).getBytes());
Message message2 = new Message("base","Tag1",("Hello World"+2).getBytes());
Message message3 = new Message("base","Tag1",("Hello World"+3).getBytes());
messageList.add(message1);
messageList.add(message2);
messageList.add(message3);
// 5.发送批量消息
SendResult result = defaultMQProducer.send(messageList);
System.out.println(result);
// 6.关闭生产者producer
defaultMQProducer.shutdown();
}
}
如果消息大于4MB
public class ListSplitter implements Iterator<List<Message>> {
private final int SIZE_LIMIT = 1024 * 1024 * 4;
private final List<Message> messages;
private int currIndex;
public ListSplitter(List<Message> messages) {
this.messages = messages;
}
@Override
public boolean hasNext() {
return currIndex < messages.size();
}
@Override
public List<Message> next() {
int nextIndex = currIndex;
int totalSize = 0;
for (; nextIndex < messages.size(); nextIndex++) {
Message message = messages.get(nextIndex);
int tmpSize = message.getTopic().length() + message.getBody().length;
Map<String, String> properties = message.getProperties();
for (Map.Entry<String, String> entry : properties.entrySet()) {
tmpSize += entry.getKey().length() + entry.getValue().length();
}
tmpSize = tmpSize + 20; // 增加日志的开销20字节
if (tmpSize > SIZE_LIMIT) {
//单个消息超过了最大的限制
//忽略,否则会阻塞分裂的进程
if (nextIndex - currIndex == 0) {
//假如下一个子列表没有元素,则添加这个子列表然后退出循环,否则只是退出循环
nextIndex++;
}
break;
}
if (tmpSize + totalSize > SIZE_LIMIT) {
break;
} else {
totalSize += tmpSize;
}
}
List<Message> subList = messages.subList(currIndex, nextIndex);
currIndex = nextIndex;
return subList;
}
}
//把大的消息分裂成若干个小的消息
ListSplitter splitter = new ListSplitter(messages);
while (splitter.hasNext()) {
try {
List<Message> listItem = splitter.next();
producer.send(listItem);
} catch (Exception e) {
e.printStackTrace();
//处理error
}
}
3.6过滤消息
在大多数情况下,TAG是一个简单而有用的设计,其可以来选择您想要的消息。例如:
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("CID_EXAMPLE");
consumer.subscribe("TOPIC", "TAGA || TAGB || TAGC");
消费者将接收包含TAGA或TAGB或TAGC的消息。但是限制是一个消息只能有一个标签,这对于复杂的场景可能不起作用。在这种情况下,可以使用SQL表达式筛选消息。SQL特性可以通过发送消息时的属性来进行计算。在RocketMQ定义的语法下,可以实现一些简单的逻辑.
package com.kebo.filter.sql;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.MessageSelector;
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.common.message.MessageExt;
import java.util.List;
/**
* @description: 消息接收者
* @author: kb
* @create: 2021-01-25 19:09
**/
public class Consumer {
public static void main(String[] args) throws Exception{
// 1. 创建消费者Consumer,制定消费者组名
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer("defaultGroup");
// 2. 指定Nameserver地址
defaultMQPushConsumer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3. 订阅主题Topic和Tag
//defaultMQPushConsumer.subscribe("base", "Tag1||Tag2");
defaultMQPushConsumer.subscribe("base", MessageSelector.bySql("i>5"));
// 4. 设置回调函数,处理消息
defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
//接受消息内容
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (int i = 0; i < list.size(); i++) {
System.out.println(new String(list.get(i).getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 5. 启动消费者consumer
defaultMQPushConsumer.start();
}
}
package com.kebo.filter.sql;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
/**
* @description: 发送批量消息
* @author: kb
* @create: 2021-01-24 20:54
**/
public class SyncProducer {
public static void main(String[] args) throws Exception {
// 1.创建消息生产者producer,并制定生产者组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("defaultGroup");
// 2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("192.168.31.205:9876;192.168.31.222:9876");
// 3.启动producer
defaultMQProducer.start();
for (int i = 0; i < 10; i++) {
// 4.创建消息对象,指定主题Topic、Tag和消息体
Message message = new Message("base", "Tag2", ("Hello World" + i).getBytes());
message.putUserProperty("i", String.valueOf(i));
// 5.发送批量消息
SendResult result = defaultMQProducer.send(message);
System.out.println(result);
}
// 6.关闭生产者producer
defaultMQProducer.shutdown();
}
}
3.7事务消息
上图说明了事务消息的大致方案,其中分为两个流程:正常事务消息的发送及提交、事务消息的补偿流程。
1)事务消息发送及提交
(1) 发送消息(half消息)。
(2) 服务端响应消息写入结果。
(3) 根据发送结果执行本地事务(如果写入失败,此时half消息对业务不可见,本地逻辑不执行)。
(4) 根据本地事务状态执行Commit或者Rollback(Commit操作生成消息索引,消息对消费者可见)
2)事务补偿
(1) 对没有Commit/Rollback的事务消息(pending状态的消息),从服务端发起一次“回查”
(2) Producer收到回查消息,检查回查消息对应的本地事务的状态
(3) 根据本地事务状态,重新Commit或者Rollback
其中,补偿阶段用于解决消息Commit或者Rollback发生超时或者失败的情况。
3)事务消息状态
事务消息共有三种状态,提交状态、回滚状态、中间状态:
- TransactionStatus.CommitTransaction: 提交事务,它允许消费者消费此消息。
- TransactionStatus.RollbackTransaction: 回滚事务,它代表该消息将被删除,不允许被消费。
- TransactionStatus.Unknown: 中间状态,它代表需要检查消息队列来确定状态。