github代码下载地址
1.RocketMQ有三种消息
1)普通消息
2)顺序消息
3)事务消息
2.顺序消息
概念:是MQ提供的一种严格按照顺序进行发布和消费的消息类型;因此可以看出,顺序消息由两部分组成,顺序发布和
顺序消费。
3.在MQ中如何保证顺序消费
(1) 消息发送是保证是顺序的 (2) 消息被存储时保证是和发送的顺序一致 (3)消息被消费时保证和存储的顺序一致
发送消息保证是顺序的意味着对于有顺序的消息,用户要保证使用同一个线程采用同步的方式发送;而存储和发送的
顺序一致则要求在同一个线程发送过来的消息A和消息B,存储时在空间上消息A一定在消息B之前;最后消费和存储的顺
序保持一致则要求,在消息A和消息B到达Consumer之后必须按照先消费消息A在消费消息B的顺序执行
对于两个订单的消息的原始数据:a1、b1、b2、a2、a3、b3(绝对时间下发生的顺序):
1) 在发送时,a订单的消息必须保证a1 ,a2 , a3的顺序发送,b订单的消息也一样,但是a,b订单之间的消息没有顺序关系;
这意味这a,b订单的消息可以通过不同的线程发送出去
2) 在存储时,需要分别保证a,b订单各自消息的顺序,但是a,b订单之间的消息可以不保证
3)在消费时,只要保证每一个分区只有一个线程来去处理即可当然,如果a、b在一个分区中,在收到消息后也可以将他们拆分到不同线程中处理,不过要权衡一下收益
4.生产者代码
1)生产者
package com.roger.order.producer;
import com.roger.order.entity.OrderMsgDTO;
import com.roger.utils.SnowflakeIdWorker;
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 org.apache.rocketmq.remoting.common.RemotingHelper;
import java.util.ArrayList;
import java.util.List;
public class OrderMqProducer {
public static void main(String[] args) throws Exception {
DefaultMQProducer defaultMQProducer =
new DefaultMQProducer("orderMQProducerGroup");
defaultMQProducer.setNamesrvAddr("172.20.10.60:9876");
defaultMQProducer.start();
defaultMQProducer.createTopic("OrderTopic", "OrderTopic", 3);
String[] tags = new String[]{"TagC", "TagP", "TagF"};
List<OrderMsgDTO> orderMsgList = new ArrayList<>();
int orderCount = 5;
for (int i = 0; i < orderCount; i++) {
long orderId = SnowflakeIdWorker.getInstance().nextId();
OrderMqProducer.builderOrderMsgList(orderMsgList, orderId);
}
for (int i = 0; i < orderMsgList.size(); i++) {
OrderMsgDTO orderMsgDTO = orderMsgList.get(i);
String body = orderMsgDTO.toString();
Message msg = new Message("OrderTopic",
tags[i % tags.length],
"OrderKey" + i,
body.getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = defaultMQProducer.send(msg, new MessageQueueSelector() {
//List<MessageQueue> msgQueList 消息要发送的Topic下的所有分区
//Message message 消息对象
// Object args 额外的参数,用户可以自己传递参数
// 比如为了把同一个订单的消息发送到同一个分区中,
// 可以把订单号作为一个参数传递过去然后mod分区个数,
// 就可以保证把同一个订单的消息发送到同一个分区中去
@Override
public MessageQueue select(List<MessageQueue> msgQueList, Message message, Object args) {
long orderId = (long) args;
long index = orderId % msgQueList.size();
return msgQueList.get((int) index);
}
}, orderMsgDTO.getOrderId());
System.out.println(sendResult +
String.format("message [%s] send success.",
new String(msg.getBody())));
}
//defaultMQProducer.shutdown();
}
private static void builderOrderMsgList(List<OrderMsgDTO> orderMsgList, long orderId) {
orderMsgList.add(new OrderMsgDTO(orderId, "Create"));
orderMsgList.add(new OrderMsgDTO(orderId, "PayOff"));
orderMsgList.add(new OrderMsgDTO(orderId, "Finish"));
}
}
2.topic配置信息
3 运行结果- 5个订单的消息分到了三个队列(queue=0,1,2)中去了
SendResult [sendStatus=SEND_OK,
msgId=AC140A051DC818B4AAC2938813480000,
offsetMsgId=AC140A3C00002A9F00000000000297A4,
messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=0],
queueOffset=3
]
message [OrderMsgDTO(orderId=517724620921503744, msgType=Create)] send success.
SendResult [sendStatus=SEND_OK,
msgId=AC140A051DC818B4AAC2938813510001,
offsetMsgId=AC140A3C00002A9F000000000002988D,
messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=0],
queueOffset=4
]
message [OrderMsgDTO(orderId=517724620921503744, msgType=PayOff)] send success.
SendResult [sendStatus=SEND_OK,
msgId=AC140A051DC818B4AAC2938813C90002,
offsetMsgId=AC140A3C00002A9F0000000000029976,
messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=0],
queueOffset=5
]
message [OrderMsgDTO(orderId=517724620921503744, msgType=Finish)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938813EA0003, offsetMsgId=AC140A3C00002A9F0000000000029A5F, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=1], queueOffset=3]message [OrderMsgDTO(orderId=517724620925698048, msgType=Create)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938813F00004, offsetMsgId=AC140A3C00002A9F0000000000029B48, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=1], queueOffset=4]message [OrderMsgDTO(orderId=517724620925698048, msgType=PayOff)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938814000005, offsetMsgId=AC140A3C00002A9F0000000000029C31, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=1], queueOffset=5]message [OrderMsgDTO(orderId=517724620925698048, msgType=Finish)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938814A20006, offsetMsgId=AC140A3C00002A9F0000000000029D1A, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=2], queueOffset=12]message [OrderMsgDTO(orderId=517724620925698049, msgType=Create)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938815060007, offsetMsgId=AC140A3C00002A9F0000000000029E03, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=2], queueOffset=13]message [OrderMsgDTO(orderId=517724620925698049, msgType=PayOff)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938815110008, offsetMsgId=AC140A3C00002A9F0000000000029EEC, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=2], queueOffset=14]message [OrderMsgDTO(orderId=517724620925698049, msgType=Finish)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938815150009, offsetMsgId=AC140A3C00002A9F0000000000029FD5, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=0], queueOffset=6]message [OrderMsgDTO(orderId=517724620925698050, msgType=Create)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC293881546000A, offsetMsgId=AC140A3C00002A9F000000000002A0BE, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=0], queueOffset=7]message [OrderMsgDTO(orderId=517724620925698050, msgType=PayOff)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC293881549000B, offsetMsgId=AC140A3C00002A9F000000000002A1A8, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=0], queueOffset=8]message [OrderMsgDTO(orderId=517724620925698050, msgType=Finish)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938819F0000C, offsetMsgId=AC140A3C00002A9F000000000002A292, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=1], queueOffset=6]message [OrderMsgDTO(orderId=517724620925698051, msgType=Create)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC293881A30000D, offsetMsgId=AC140A3C00002A9F000000000002A37C, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=1], queueOffset=7]message [OrderMsgDTO(orderId=517724620925698051, msgType=PayOff)] send success.
SendResult [sendStatus=SEND_OK, msgId=AC140A051DC818B4AAC2938821A0000E, offsetMsgId=AC140A3C00002A9F000000000002A466, messageQueue=MessageQueue [topic=OrderTopic, brokerName=broker-a, queueId=1], queueOffset=8]message [OrderMsgDTO(orderId=517724620925698051, msgType=Finish)] send success.
5.消费者代码-两个消费者代码相同只是细微的差别
1.代码
package com.roger.order.consumer;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class OrderMqConsumer1 {
public static void main(String[] args) throws Exception{
DefaultMQPushConsumer defaultMQPushConsumer =
new DefaultMQPushConsumer("orderMQPushConsumerGroup");
defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
defaultMQPushConsumer.setNamesrvAddr("172.20.10.60:9876");
defaultMQPushConsumer.subscribe("OrderTopic","*");
defaultMQPushConsumer.registerMessageListener(new MessageListenerOrderly() {
Random r = new Random();
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgExtList, ConsumeOrderlyContext context) {
context.setAutoCommit(true);
System.out.println("当前线程名:" + Thread.currentThread().getName() + ";Receive new message:");
for(MessageExt msgExt : msgExtList){
System.out.println(String.format("Consume message [%s],TagName [%s]",
new String(msgExt.getBody()),
msgExt.getTags()));
try {
//简单业务处理逻辑
TimeUnit.SECONDS.sleep(r.nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
defaultMQPushConsumer.start();
System.out.println("OrderMqConsumer1 Started...");
}
}
2.OrderMqConsumer1运行结果-
(a) 消费了queue=0 和queue=1的数据
(b) 每个订单按照顺序执行,并且是订单号相同的消息同一个线程执行的
OrderMqConsumer1 Started...
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698048, msgType=Create)],TagName [TagC]
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698048, msgType=PayOff)],TagName [TagP]
当前线程名:ConsumeMessageThread_2;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620921503744, msgType=Create)],TagName [TagC]
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698048, msgType=Finish)],TagName [TagF]
当前线程名:ConsumeMessageThread_2;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620921503744, msgType=PayOff)],TagName [TagP]
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698051, msgType=Create)],TagName [TagC]
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698051, msgType=PayOff)],TagName [TagP]
当前线程名:ConsumeMessageThread_2;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620921503744, msgType=Finish)],TagName [TagF]
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698051, msgType=Finish)],TagName [TagF]
当前线程名:ConsumeMessageThread_2;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698050, msgType=Create)],TagName [TagC]
当前线程名:ConsumeMessageThread_2;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698050, msgType=PayOff)],TagName [TagP]
当前线程名:ConsumeMessageThread_2;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698050, msgType=Finish)],TagName [TagF]
3.OrderMqConsumer1运行结果-
OrderMqConsumer2 Started...
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698049, msgType=Create)],TagName [TagC]
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698049, msgType=PayOff)],TagName [TagP]
当前线程名:ConsumeMessageThread_1;Receive new message:
Consume message [OrderMsgDTO(orderId=517724620925698049, msgType=Finish)],TagName [TagF]