RocketMQ学习笔记 - 顺序消息

1、定义

顺序消息(FIFO 消息):是 MQ 提供的一种严格按照顺序进行发布和消费的消息类型。
顺序消息由两个部分组成:顺序发布和顺序消费。

顺序消息包含两种类型:

  • 分区顺序:一个Partition内所有的消息按照先进先出的顺序进行发布和消费
  • 全局顺序:一个Topic内所有的消息按照先进先出的顺序进行发布和消费

2、代码示例

2.1、消息实体

package com.wzl.rocketmq.order;

import java.util.ArrayList;
import java.util.List;

/**
 * 消息体
 */
public class OrderStep {

    private long orderId;
    private String desc;

    public long getOrderId() {
        return orderId;
    }

    public void setOrderId(long orderId) {
        this.orderId = orderId;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public static List<OrderStep> buildOrders() {
        List<OrderStep> list = new ArrayList<>();

        OrderStep orderStep = new OrderStep();
        orderStep.setOrderId(101L);
        orderStep.setDesc("创建");
        list.add(orderStep);


        orderStep = new OrderStep();
        orderStep.setOrderId(101L);
        orderStep.setDesc("付款");
        list.add(orderStep);


        orderStep = new OrderStep();
        orderStep.setOrderId(102L);
        orderStep.setDesc("创建");
        list.add(orderStep);


        orderStep = new OrderStep();
        orderStep.setOrderId(101L);
        orderStep.setDesc("发货");
        list.add(orderStep);

        orderStep = new OrderStep();
        orderStep.setOrderId(102L);
        orderStep.setDesc("发货");
        list.add(orderStep);

        orderStep = new OrderStep();
        orderStep.setOrderId(101L);
        orderStep.setDesc("结束");
        list.add(orderStep);

        orderStep = new OrderStep();
        orderStep.setOrderId(102L);
        orderStep.setDesc("结束");
        list.add(orderStep);

        return list;
    }

    @Override
    public String toString() {
        return "OrderStep{" +
                "orderId=" + orderId +
                ", desc='" + desc + '\'' +
                '}';
    }
}

2.2、生产者

package com.wzl.rocketmq.order;

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;

/**
 * 顺序消息--生产者
 */
public class OrderProducer {

    public static void sendTagAMessage() throws MQClientException {
        //定义producer
        DefaultMQProducer producer = new DefaultMQProducer("order_group101");

        //要设置NameServer地址,多个;分割
        producer.setNamesrvAddr("192.168.12.121:9876");

        //启动
        producer.start();

        //发送消息
        for (int i = 0; i < OrderStep.buildOrders().size(); i++) {
            try {
                OrderStep orderStep = OrderStep.buildOrders().get(i);
                String body = orderStep + "";

                Message msg = new Message("OrderTopic", "TagOrder", "i" + i, body.getBytes());

                SendResult sendResult = producer.send(msg, (mqs, message, args) -> {
                    long orderId = (long) args;
                    long index = orderId % mqs.size();//订单号和queue数量进行取模
                    return mqs.get((int) index);
                }, orderStep.getOrderId());

                System.out.println("OrderProducer发送消息Order:" + sendResult);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        //关闭生产者
        producer.shutdown();
    }

    public static void main(String[] args) throws MQClientException {
        //发送tagA消息
        sendTagAMessage();
    }

}

2.3、消费者

package com.wzl.rocketmq.order;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;


/**
 * 顺序消息--消费者
 */
public class OrderConsumer {

    public static void main(String[] args) throws MQClientException {
        //声明并初始化一个consumer
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("order_consumer101");

        //要设置NameServer地址,多个;分割
        consumer.setNamesrvAddr("192.168.12.121:9876");

        //设置consumer所订阅的Topic和Tag,*代表全部的Tag
        consumer.subscribe("OrderTopic", "TagOrder");

        //集群订阅
        consumer.setMessageModel(MessageModel.CLUSTERING);

        //这里设置的是一个consumer的消费策略
        //CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,即跳过历史消息
        //CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
        //CONSUME_FROM_TIMESTAMP 从某个时间点开始消费,和setConsumeTimestamp()配合使用,默认是半个小时以前
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);

        //设置一个Listener,主要进行消息的逻辑处理
        consumer.registerMessageListener((MessageListenerOrderly) (list, context) -> {
            for (MessageExt messageExt : list) {
                String messageBody = new String(messageExt.getBody());
                System.out.println("线程名称: " + Thread.currentThread().getName() + " 消费消息: " + messageBody);//输出消息内容
            }

            //返回消费状态
            return ConsumeOrderlyStatus.SUCCESS;
        });

        //调用start()方法启动consumer
        consumer.start();

        System.out.println("OrderConsumer Started.");
    }
}

2.3、测试结果

生产者发送的消息都是刻意被打乱的
为了方便观察,我们启动2个消费者

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

结果发现:由于具有相同的OrderId取模在同一个queue中,消费也是不同订单号被不同的消费者有序消费的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值