RocketMq順序消息解決方案

一、概念

順序消費可以從業務層次分爲兩種:全局順序消息、局部順序消息

  1. 全局順序消息:顧名思義,就是產生消息的順序和消費消息的順序一致,比如用戶訂單,大致分爲:創建訂單、支付、打包待發貨、已發貨、用戶簽收,業務上處理訂單時必須按照先後次序來生產、消費消息,不能出現已經消費了支付消息,然後消費創建訂單消息
  2. 局部順序消息:只要保證同一個訂單(相同訂單號)生產和消費的先後次序即可
  • 保證全局消息順序方案:創建只有一個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,不應該這樣使用,後續補上優化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章