一、概念
順序消費可以從業務層次分爲兩種:全局順序消息、局部順序消息
- 全局順序消息:顧名思義,就是產生消息的順序和消費消息的順序一致,比如用戶訂單,大致分爲:創建訂單、支付、打包待發貨、已發貨、用戶簽收,業務上處理訂單時必須按照先後次序來生產、消費消息,不能出現已經消費了支付消息,然後消費創建訂單消息
- 局部順序消息:只要保證同一個訂單(相同訂單號)生產和消費的先後次序即可
- 保證全局消息順序方案:創建只有一個message queue的topic,然後生產和消費時只能是單線程,這樣就無法高效的處理訂單,效率極低。
- 保證局部消息順序方案:在發送消息時,保證同一業務id(訂單ID、用戶身份證號、手機號,根據業務場景來定)的消息發送到同一個queue;在消費時,保證同一個queue讀取的消息不被併發處理即可,這樣同一業務id的消息都是有序的
二、局部消息順序具體實現
1、pom.xml
springboot、fastjson等依賴包沒有粘出來
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.2</version>
<exclusions>
<exclusion>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
</exclusion>
<exclusion>
<artifactId>spring-boot-starter-validation</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
<exclusion>
<artifactId>spring-boot-starter</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
2、訂單bean
package com.cn.dl.springbootdemo.bean;
import com.cn.dl.springbootdemo.enums.EnumOrderType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* Created by yanshao on 2020-05-07.
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Order implements Serializable {
private static final long serialVersionUID = -6955843080469225187L;
/**
* 訂單ID,UUID
* */
private String orderId;
/**
* {@link EnumOrderType#getCode()}
* */
private String orderType;
/**
* {@link EnumOrderType#getDesc()}
* */
private String orderDesc;
}
3、訂單類型枚舉
package com.cn.dl.springbootdemo.enums;
import lombok.Getter;
/**
* 訂單類型
* Created by yanshao on 2020-05-07.
*/
public enum EnumOrderType {
CREATE("01","創建訂單"),
PAY("02","支付訂單"),
BALE("03","已打包,待發貨"),
SEND("04","包裹已發貨")
;
@Getter
private String code;
@Getter
private String desc;
EnumOrderType(String code, String desc) {
this.code = code;
this.desc = desc;
}
public static EnumOrderType getByCode(String code){
EnumOrderType[] orderTypes = EnumOrderType.values();
for(EnumOrderType orderType : orderTypes){
if(orderType.getCode().equals(code)){
return orderType;
}
}
return null;
}
}
4、常量參數
package com.cn.dl.springbootdemo.constant;
/**
* Created by yanshao on 2020-05-07.
*/
public class OrderConstant {
public static final String ORDER_TOPIC = "order_msg";
public static final String ORDER_CONSUMER_GROUP = "order_msg_consumer";
}
5、訂單消息發送
package com.cn.dl.springbootdemo.mq;
import com.alibaba.fastjson.JSONObject;
import com.cn.dl.springbootdemo.bean.Order;
import com.cn.dl.springbootdemo.constant.OrderConstant;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* send order message
*/
@Component
public class OrderMessageProducer{
private static final Logger logger = LoggerFactory.getLogger(OrderMessageProducer.class);
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 發送順序消息,即同一個訂單號的消息路由到同一個消息隊列
* */
public boolean sendOrderMessage(Order order){
try {
String orderInfo = JSONObject.toJSONString(order);
logger.info("order info :{}",orderInfo);
SendResult sendResult = rocketMQTemplate.syncSendOrderly(OrderConstant.ORDER_TOPIC,orderInfo,order.getOrderId(),3000);
logger.info("orderId: {}, queueId: {}",order.getOrderId(),sendResult.getMessageQueue().getQueueId());
return sendResult.getSendStatus() == SendStatus.SEND_OK;
}catch (Exception e){
logger.error("send message error ",e);
}
return false;
}
/**
* 隨機路由到不同消息隊列
* */
public boolean randomSendOrderMessage(Order order){
try {
String orderInfo = JSONObject.toJSONString(order);
logger.info("order info :{}",orderInfo);
SendResult sendResult = rocketMQTemplate.syncSend(OrderConstant.ORDER_TOPIC,orderInfo);
logger.info("orderId: {}, queueId: {}",order.getOrderId(),sendResult.getMessageQueue().getQueueId());
return sendResult.getSendStatus() == SendStatus.SEND_OK;
}catch (Exception e){
logger.error("send message error ",e);
}
return false;
}
}
org.apache.rocketmq.spring.core.RocketMQTemplate#syncSendOrderly(java.lang.String, java.lang.Object, java.lang.String, long)
hashKey是傳入的訂單ID,然後對訂單ID計算hashCode值,然後對hashCode取模,返回對應隊列。
public SendResult syncSendOrderly(String destination, Object payload, String hashKey, long timeout) {
Message<?> message = this.doConvert(payload, (Map)null, (MessagePostProcessor)null);
return this.syncSendOrderly(destination, message, hashKey, (long)this.producer.getSendMsgTimeout());
}
org.apache.rocketmq.client.producer.selector.SelectMessageQueueByHash#select
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
int value = arg.hashCode();
if (value < 0) {
value = Math.abs(value);
}
value %= mqs.size();
return (MessageQueue)mqs.get(value);
}
6、producer測試
package com.cn.dl.springbootdemo.mq;
import com.cn.dl.springbootdemo.bean.Order;
import com.cn.dl.springbootdemo.enums.EnumOrderType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderMessageProducerTest {
private static final Logger logger = LoggerFactory.getLogger(OrderMessageProducerTest.class);
@Autowired
private OrderMessageProducer orderMessageProducer;
@Test
public void sendOrderMessage() throws InterruptedException {
int i = 0;
while (i < 20){
sendOrderMessages();
TimeUnit.MILLISECONDS.sleep(200);
i++;
}
}
@Test
public void randomSendOrderMessage() throws InterruptedException {
int i = 0;
while (i < 2){
randomSendOrderMsg();
TimeUnit.MILLISECONDS.sleep(200);
i++;
}
}
private void sendOrderMessages(){
//The order id is a random UUID
String orderId = UUID.randomUUID().toString().replace("-","");
boolean createMsgSendResult = orderMessageProducer.sendOrderMessage(getOrder(orderId,EnumOrderType.CREATE));
logger.info("Send result[create message]: {}",createMsgSendResult);
boolean payMsgSendResult = orderMessageProducer.sendOrderMessage(getOrder(orderId,EnumOrderType.PAY));
logger.info("Send result[pay message]: {}",payMsgSendResult);
boolean bailMsgSendResult = orderMessageProducer.sendOrderMessage(getOrder(orderId,EnumOrderType.BALE));
logger.info("Send result[bail message]: {}",bailMsgSendResult);
boolean sendMsgSendResult = orderMessageProducer.sendOrderMessage(getOrder(orderId,EnumOrderType.SEND));
logger.info("Send result[send message]: {}",sendMsgSendResult);
}
private void randomSendOrderMsg(){
//The order id is a random UUID
String orderId = UUID.randomUUID().toString().replace("-","");
boolean createMsgSendResult = orderMessageProducer.randomSendOrderMessage(getOrder(orderId,EnumOrderType.CREATE));
logger.info("Send result[create message]: {}",createMsgSendResult);
boolean payMsgSendResult = orderMessageProducer.randomSendOrderMessage(getOrder(orderId,EnumOrderType.PAY));
logger.info("Send result[pay message]: {}",payMsgSendResult);
boolean bailMsgSendResult = orderMessageProducer.randomSendOrderMessage(getOrder(orderId,EnumOrderType.BALE));
logger.info("Send result[bail message]: {}",bailMsgSendResult);
boolean sendMsgSendResult = orderMessageProducer.randomSendOrderMessage(getOrder(orderId,EnumOrderType.SEND));
logger.info("Send result[send message]: {}",sendMsgSendResult);
}
private Order getOrder(String orderId,EnumOrderType orderType){
return Order.builder()
.orderId(orderId)
.orderType(orderType.getCode())
.orderDesc(orderType.getDesc())
.build();
}
}
發送順序消息,觀察message queue的offset以及queueId變化,通過日誌發送,同一個訂單ID的消息都路由到同一個message queue
15:47:44.515 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"創建訂單","orderId":"3178a9f4a7504c718c39cca97aab5527","orderType":"01"}
15:47:44.555 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 3178a9f4a7504c718c39cca97aab5527, queueId: 0
15:47:44.556 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[40] -Send result[create message]: true
15:47:44.556 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"支付訂單","orderId":"3178a9f4a7504c718c39cca97aab5527","orderType":"02"}
15:47:44.574 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 3178a9f4a7504c718c39cca97aab5527, queueId: 0
15:47:44.574 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[43] -Send result[pay message]: true
15:47:44.574 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"已打包,待發貨","orderId":"3178a9f4a7504c718c39cca97aab5527","orderType":"03"}
15:47:44.585 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 3178a9f4a7504c718c39cca97aab5527, queueId: 0
15:47:44.586 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[46] -Send result[bail message]: true
15:47:44.586 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"包裹已發貨","orderId":"3178a9f4a7504c718c39cca97aab5527","orderType":"04"}
15:47:44.596 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 3178a9f4a7504c718c39cca97aab5527, queueId: 0
15:47:44.596 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[49] -Send result[send message]: true
15:47:44.799 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"創建訂單","orderId":"43cd12eab881434abae9d5551833ba1e","orderType":"01"}
15:47:44.825 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 43cd12eab881434abae9d5551833ba1e, queueId: 2
15:47:44.826 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[40] -Send result[create message]: true
15:47:44.826 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"支付訂單","orderId":"43cd12eab881434abae9d5551833ba1e","orderType":"02"}
15:47:44.839 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 43cd12eab881434abae9d5551833ba1e, queueId: 2
15:47:44.839 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[43] -Send result[pay message]: true
15:47:44.840 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"已打包,待發貨","orderId":"43cd12eab881434abae9d5551833ba1e","orderType":"03"}
15:47:44.852 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 43cd12eab881434abae9d5551833ba1e, queueId: 2
15:47:44.852 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[46] -Send result[bail message]: true
15:47:44.852 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[27] -order info :{"orderDesc":"包裹已發貨","orderId":"43cd12eab881434abae9d5551833ba1e","orderType":"04"}
15:47:44.863 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[29] -orderId: 43cd12eab881434abae9d5551833ba1e, queueId: 2
15:47:44.863 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[49] -Send result[send message]: true
在rocketmq-console(rocketMq搭建)發現每個queue的offset也是4的倍數
發送非順序消息,路由到的message queue是隨機的
16:06:08.117 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"創建訂單","orderId":"4994f057936648d4a9de36f9e6d8bb71","orderType":"01"}
16:06:08.239 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 4994f057936648d4a9de36f9e6d8bb71, queueId: 4
16:06:08.239 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[68] -Send result[create message]: true
16:06:08.239 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"支付訂單","orderId":"4994f057936648d4a9de36f9e6d8bb71","orderType":"02"}
16:06:08.252 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 4994f057936648d4a9de36f9e6d8bb71, queueId: 5
16:06:08.252 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[71] -Send result[pay message]: true
16:06:08.252 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"已打包,待發貨","orderId":"4994f057936648d4a9de36f9e6d8bb71","orderType":"03"}
16:06:08.267 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 4994f057936648d4a9de36f9e6d8bb71, queueId: 6
16:06:08.269 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[74] -Send result[bail message]: true
16:06:08.270 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"包裹已發貨","orderId":"4994f057936648d4a9de36f9e6d8bb71","orderType":"04"}
16:06:08.282 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 4994f057936648d4a9de36f9e6d8bb71, queueId: 7
16:06:08.283 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[77] -Send result[send message]: true
16:06:08.486 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"創建訂單","orderId":"7a95c7bfbef043ac82f9d16fe476c0cc","orderType":"01"}
16:06:08.503 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 7a95c7bfbef043ac82f9d16fe476c0cc, queueId: 0
16:06:08.504 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[68] -Send result[create message]: true
16:06:08.504 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"支付訂單","orderId":"7a95c7bfbef043ac82f9d16fe476c0cc","orderType":"02"}
16:06:08.518 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 7a95c7bfbef043ac82f9d16fe476c0cc, queueId: 1
16:06:08.519 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[71] -Send result[pay message]: true
16:06:08.520 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"已打包,待發貨","orderId":"7a95c7bfbef043ac82f9d16fe476c0cc","orderType":"03"}
16:06:08.533 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 7a95c7bfbef043ac82f9d16fe476c0cc, queueId: 2
16:06:08.535 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[74] -Send result[bail message]: true
16:06:08.535 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[46] -order info :{"orderDesc":"包裹已發貨","orderId":"7a95c7bfbef043ac82f9d16fe476c0cc","orderType":"04"}
16:06:08.547 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducer[48] -orderId: 7a95c7bfbef043ac82f9d16fe476c0cc, queueId: 3
16:06:08.547 [main] INFO com.cn.dl.springbootdemo.mq.OrderMessageProducerTest[77] -Send result[send message]: true
7、訂單消息消費
package com.cn.dl.springbootdemo.mq;
import com.cn.dl.springbootdemo.constant.OrderConstant;
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.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* Created by yanshao on 2020-05-07.
*/
@Component
@RocketMQMessageListener(
topic = OrderConstant.ORDER_TOPIC,
consumerGroup = OrderConstant.ORDER_CONSUMER_GROUP,
consumeMode = ConsumeMode.ORDERLY
)
public class OrderMessageCustomer implements RocketMQListener<MessageExt>, RocketMQPushConsumerLifecycleListener {
private static final Logger logger = LoggerFactory.getLogger(OrderMessageCustomer.class);
@Autowired
private OrderMessageCustomer orderMessageCustomer;
@Override
public void onMessage(MessageExt messageExt) {
String msg = null;
try {
msg = new String(messageExt.getBody(), StandardCharsets.UTF_8.name());
logger.info("order info: {}",msg);
//測試異常情況
throw new RuntimeException();
}catch (Exception e){
logger.warn("consume message error msgId:{} orderInfo:{}",messageExt.getMsgId(),msg,e);
throw new RuntimeException("consumption failure!");
}
}
@Override
public void prepareStart(DefaultMQPushConsumer defaultMQPushConsumer) {
//After failed consumption, the number of retries
defaultMQPushConsumer.setMaxReconsumeTimes(4);
//set the minimum number of consumer threads to 8
defaultMQPushConsumer.setConsumeThreadMin(8);
defaultMQPushConsumer.setMessageListener(new MessageListenerOrderly() {
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> messageExts, ConsumeOrderlyContext consumeOrderlyContext) {
try {
for(MessageExt messageExt : messageExts){
long now = System.currentTimeMillis();
orderMessageCustomer.onMessage(messageExt);
long costTime = System.currentTimeMillis() - now;
logger.info("consume message threadName:{} msgId: {} costTime: {}",
Thread.currentThread().getName(),messageExt.getMsgId(), costTime);
}
}catch (Exception e){
logger.warn("consume message error",e);
return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
logger.info("start order consumption!");
}
}
prepareStart方法中的邏輯就是消費時給message queue增加了鎖,這樣保證了每個message queue同一時間有且僅有一個線程在消費
org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer.DefaultMessageListenerOrderly
8、消費測試
package com.cn.dl.springbootdemo.mq;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderMessageCustomerTest {
@Test
public void onMessage() throws InterruptedException {
TimeUnit.MINUTES.sleep(10);
}
}
同一時間只有一個線程消費同一訂單id的消息
17:23:33.128 [ConsumeMessageThread_4] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"創建訂單","orderId":"49b8f4f9b8274036a2eb6b415a1e4622","orderType":"01"}
17:23:33.128 [ConsumeMessageThread_4] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_4 msgId: AC111128823F18B4AAC222A18E7800EC costTime: 0
17:23:33.142 [ConsumeMessageThread_5] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"支付訂單","orderId":"49b8f4f9b8274036a2eb6b415a1e4622","orderType":"02"}
17:23:33.142 [ConsumeMessageThread_5] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_5 msgId: AC111128823F18B4AAC222A18E8900EE costTime: 0
17:23:33.153 [ConsumeMessageThread_6] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"已打包,待發貨","orderId":"49b8f4f9b8274036a2eb6b415a1e4622","orderType":"03"}
17:23:33.153 [ConsumeMessageThread_6] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_6 msgId: AC111128823F18B4AAC222A18E9500F1 costTime: 0
17:23:33.170 [ConsumeMessageThread_7] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"包裹已發貨","orderId":"49b8f4f9b8274036a2eb6b415a1e4622","orderType":"04"}
17:23:33.170 [ConsumeMessageThread_7] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_7 msgId: AC111128823F18B4AAC222A18EA200F4 costTime: 0
17:23:33.912 [ConsumeMessageThread_1] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"創建訂單","orderId":"3920dcff817f4e85ac2537d497410262","orderType":"01"}
17:23:33.913 [ConsumeMessageThread_1] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_1 msgId: AC111128823F18B4AAC222A1918C0120 costTime: 1
17:23:33.926 [ConsumeMessageThread_2] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"支付訂單","orderId":"3920dcff817f4e85ac2537d497410262","orderType":"02"}
17:23:33.927 [ConsumeMessageThread_2] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_2 msgId: AC111128823F18B4AAC222A191990122 costTime: 0
17:23:33.940 [ConsumeMessageThread_3] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"已打包,待發貨","orderId":"3920dcff817f4e85ac2537d497410262","orderType":"03"}
17:23:33.940 [ConsumeMessageThread_3] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_3 msgId: AC111128823F18B4AAC222A191A70125 costTime: 0
17:23:33.950 [ConsumeMessageThread_4] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[42] -order info: {"orderDesc":"包裹已發貨","orderId":"3920dcff817f4e85ac2537d497410262","orderType":"04"}
17:23:33.950 [ConsumeMessageThread_4] INFO com.cn.dl.springbootdemo.mq.OrderMessageCustomer[63] -consume message threadName:ConsumeMessageThread_4 msgId: AC111128823F18B4AAC222A191B30128 costTime: 0
處理訂單異常情況下,也是按照順序消息
異常日誌比較多,沒有貼
ps: 僅僅是demo,可能有bug,對於消息消費consumer類,只是爲了驗證功能注入了orderMessageCustomer,不應該這樣使用,後續補上優化