一、概念

顺序消费可以从业务层次分为两种:全局顺序消息、局部顺序消息

  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的倍数

java rocketmq consumer消息不消费 rocketmq消息顺序被消费_spring

发送非顺序消息,路由到的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

java rocketmq consumer消息不消费 rocketmq消息顺序被消费_spring_02

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的消息

java rocketmq consumer消息不消费 rocketmq消息顺序被消费_apache_03

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

处理订单异常情况下,也是按照顺序消息

java rocketmq consumer消息不消费 rocketmq消息顺序被消费_apache_04

异常日志比较多,没有贴

 

ps: 仅仅是demo,可能有bug,对于消息消费consumer类,只是为了验证功能注入了orderMessageCustomer,不应该这样使用,后续补上优化

java rocketmq consumer消息不消费 rocketmq消息顺序被消费_java_05