RocketMq消息无序,以及消息消费

文章讲述了在使用ApacheRocketMQ进行延时消息生产时,观察到消费者接收到消息的顺序与预期不符的情况,特别关注了集群模式下消费者组内的消息分配机制。
摘要由CSDN通过智能技术生成

做延时消息的时候,做了一个for循环,生成消息,代码如下:

import lombok.SneakyThrows;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.springframework.stereotype.Component;

@Component
public class Delayproducer {

    @SneakyThrows
    public void sendDelayMsg() {
        //延时时间:延时十分钟
        Long delayTime = Long.valueOf(1000 * 60 * 10);
        DefaultMQProducer producer = new DefaultMQProducer("delay-producer");
        producer.setNamesrvAddr("localhost:9876");
        producer.start();
        for(int i=0;i<5;i++){
            String msg = i + " 延时消息:"+System.currentTimeMillis();
            Message message = new Message("delay-topic","delay-tag",msg.getBytes());
            // 默认值为“1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”,18个level
            // 此时默认消息30s后发送
            message.setDelayTimeLevel(4);
            producer.send(message,delayTime);
        }
        producer.shutdown();
    }
}

设置消息为30秒的延时消息,但是消费者收到消息,打印信息如下:
集群消费者log:

集群消费者消费信息[1 延时消息:1704173274429]
集群消费者消费信息[0 延时消息:1704173273958]
集群消费者消费信息[2 延时消息:1704173274431]
集群消费者消费信息[3 延时消息:1704173274433]
集群消费者消费信息[4 延时消息:1704173274435]

广播消费者log

广播消费者消费信息[1 延时消息:1704173274429]
广播消费者消费信息[2 延时消息:1704173274431]
广播消费者消费信息[3 延时消息:1704173274433]
广播消费者消费信息[0 延时消息:1704173273958]
广播消费者消费信息[4 延时消息:1704173274435]

两边消息都不是按顺序输出的。

消费组里多个消费者

当一个消费者组内,存在多个消费者时:XXX相同

//实例化消息生产者,指定消费者组名:XXX
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("XXX");

生产者发送五条消息。以下为消费者消费信息:

//广播消费者1
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("broadcasting_consumer");
广播消费者消费信息[1 延时消息:1704181667275]
广播消费者消费信息[3 延时消息:1704181667277]
广播消费者消费信息[2 延时消息:1704181667276]
广播消费者消费信息[0 延时消息:1704181667267]
广播消费者消费信息[4 延时消息:1704181667278]
//广播消费者2
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("broadcasting_consumer");
广播消费者消费信息222[1 延时消息:1704181667275]
广播消费者消费信息222[0 延时消息:1704181667267]
广播消费者消费信息222[3 延时消息:1704181667277]
广播消费者消费信息222[2 延时消息:1704181667276]
广播消费者消费信息222[4 延时消息:1704181667278]
//集群消费者1
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ClusterConsumer");
集群消费者消费信息[0 延时消息:1704181667267]
集群消费者消费信息[3 延时消息:1704181667277]
集群消费者消费信息[4 延时消息:1704181667278]
//集群消费者2
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ClusterConsumer");
集群消费者消费信息222[2 延时消息:1704181667276]
集群消费者消费信息222[1 延时消息:1704181667275]

集群模式消费者,同一消费者组中一个消费者只能消费一个管道的消息

如图,在dashboard中,当前消费者组,消费的topic下,设置队列,三个写入队列,三个读取队列
在这里插入图片描述
但此时,我只有两个集群消费者
ClusterConsumer和ClusterConsumer2, 此时生产者循环发送五个消息:
以下为两个消费者log

ClusterConsumer.java
集群消费者消费信息[4 延时消息:1704188351002]
集群消费者消费信息[1 延时消息:1704188350992]
来自管道信息:MessageQueue [topic=delay-topic, brokerName=ZEE000-LF3SZELS, queueId=2]
来自管道信息:MessageQueue [topic=delay-topic, brokerName=ZEE000-LF3SZELS, queueId=2]
集群消费者消费信息222[0 延时消息:1704188349981]
来自管道信息:MessageQueue [topic=delay-topic, brokerName=ZEE000-LF3SZELS, queueId=1]
集群消费者消费信息222[2 延时消息:1704188350995]
来自管道信息:MessageQueue [topic=delay-topic, brokerName=ZEE000-LF3SZELS, queueId=0]
集群消费者消费信息222[3 延时消息:1704188350998]
来自管道信息:MessageQueue [topic=delay-topic, brokerName=ZEE000-LF3SZELS, queueId=1]

在RocketMQ中,队列负载的指导思想:以消费组为维度,一个消费者能分配多个队列,但一个队列只会分配给一个消费者。故一个topic的队列数量直接决定了其支持的消费者的最大数,如果topic的队列数量小于消费者的数量,那部分消费者将无法消费消息。

RocketMQ可以通过设置顺序消息来保证消息消费顺序。即按照消息的发送顺序消费消息,这种方式只能保证顺序消息的有序消费,普通消息消费仍然是无序的。 在RocketMQ中,顺序消息是指在同一个消息队列中,按顺序发送的消息。如果我们需要保证消息顺序消费,需要做以下几个步骤: 1. 创建顺序消息生产者 ```java DefaultMQProducer producer = new DefaultMQProducer("producer_group"); producer.setNamesrvAddr("localhost:9876"); producer.start(); ``` 2. 设置顺序消息 ```java Message message = new Message("topic", "tag", "key", "body".getBytes()); // 设置顺序消息的业务ID,用来保证消息发送的顺序 message.setKeys("order_id"); // 发送顺序消息 SendResult sendResult = producer.send(message, new MessageQueueSelector() { @Override public MessageQueue select(List<MessageQueue> list, Message message, Object o) { // 获取订单ID String orderId = (String) o; // 计算订单ID的hash值 int index = Math.abs(orderId.hashCode()) % list.size(); // 选择消息队列 return list.get(index); } }, "order_id"); ``` 3. 创建顺序消息消费者 ```java DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_group"); consumer.setNamesrvAddr("localhost:9876"); consumer.subscribe("topic", "tag"); consumer.registerMessageListener(new MessageListenerOrderly() { @Override public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext context) { // 消费消息 for (MessageExt messageExt : list) { System.out.println(new String(messageExt.getBody())); } // 返回消费状态 return ConsumeOrderlyStatus.SUCCESS; } }); consumer.start(); ``` 在顺序消息的发送端,我们需要设置顺序消息的业务ID,并使用`MessageQueueSelector`选择消息队列。在顺序消息消费端,我们需要注册`MessageListenerOrderly`监听器,按照顺序消费消息,最后返回消费状态。 需要注意的是,为了保证顺序消息顺序性,我们需要保证同一个业务ID的消息被发送到同一个消息队列中,这样才能保证消息消费顺序
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值