Rocket消息的顺序性

本文讨论了业务中消息顺序消费的重要性,包括保证业务逻辑一致性、数据完整性和处理依赖消息的情况。介绍了使用全局有序和局部有序策略,以及通过RocketMQ中的MessageQueueSelector实现顺序消费的示例,强调了单线程消费和分区顺序消费对并发性能的影响。
摘要由CSDN通过智能技术生成

首先为什么要保证消息的顺序消费?

1、业务的逻辑的依赖性:某些业务的逻辑需要要求消息顺序消费执行,比如订单的下单过程,每一步都需要按照步骤执行,以保证顺序的一致性

2、数据一致性:消息的顺序消费可以保证数据一致性,避免数据的错乱。比如一些业务的执行按照消息顺序执行存储数据过程,那么就可以避免并发上带来的数据一致性问题

3、依赖多个消息:一些业务上会存在多个消息同时执行的情况,那么就需要保证这些消息的正确顺序执行。比如电商上订单创建、付款请求、完成订单确认,这三个步骤都会产生消息发送到MQ内,那么就必须保证这些消息的顺序执行

那么如何保证消息的顺序消费呢?

1、全局有序:消费的所有消息都严格按照发送消息的顺序执行

这个是用一个for循环将所有消息放在同一个消息队列中,这样保证消息的顺序消费

import org.apache.rocketmq.client.producer.DefaultMQProducer;

import org.apache.rocketmq.client.producer.MessageQueueSelector;

import org.apache.rocketmq.client.producer.SendResult;

import org.apache.rocketmq.common.message.Message;

import org.apache.rocketmq.common.message.MessageQueue;

import org.apache.rocketmq.remoting.common.RemotingHelper;

import java.util.List;

public class OrderProducer {

public static void main(String[] args) throws Exception {

// 创建一个RocketMQ的消息生产者实例

DefaultMQProducer producer = new DefaultMQProducer("OrderProducerGroup");

// 设置NameServer的地址

producer.setNamesrvAddr("localhost:9876");

// 启动生产者实例

producer.start();

// 发送消息

List messages = generateMessages();

for (Message message : messages) {

// 使用MessageQueueSelector来选择消息队列

SendResult sendResult = producer.send(

message,

new MessageQueueSelector() {

@Override

public MessageQueue select(List mqs, Message msg, Object arg) {

// 这里可以根据自定义逻辑选择要发送的消息队列,确保消息按照正确的顺序发送

return mqs.get(0); // 这里简单地选择第一条消息队列

}

},

null);

System.out.printf("SendResult: %s%n", sendResult);

}

// 关闭生产者实例

producer.shutdown();

}

private static List generateMessages() throws Exception {

// 生成一些有序的消息示例

List messages = new ArrayList<>();

messages.add(new Message("TopicTest", "TagA", "Order001", "Hello RocketMQ 1".getBytes(RemotingHelper.DEFAULT_CHARSET)));

messages.add(new Message("TopicTest", "TagA", "Order002", "Hello RocketMQ 2".getBytes(RemotingHelper.DEFAULT_CHARSET)));

messages.add(new Message("TopicTest", "TagA", "Order003", "Hello RocketMQ 3".getBytes(RemotingHelper.DEFAULT_CHARSET)));

return messages;

}

}

2、局部有序:消息的部分消息按照发送顺序执行

局部消费意味着消息给不同的消费者并行地消费,但在每个消费者内部保证顺序。

在局部顺序下,消息可能会被分发到不同的消费者实例中,每个消费者实例负责处理特定的消息,在每个消费者内部,消费者线程会按照消息顺序消费,保证每个实例内部的消费是顺序的。这样设计可以提高整体的消息处理并发性。

那么什么时候适合局部有序呢?

比如订单消息可以被分为“支付”和“发货”;那这两个消息可以被发给不同的消费者去消费,这样分组的消息可以被顺序消费,也可以保证整体的消息的顺序

下面的例子

import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.remoting.common.RemotingHelper; public class LocalConsumer { public static void main(String[] args) throws Exception { // 创建一个RocketMQ的消息生产者实例 DefaultMQProducer producer = new DefaultMQProducer("LocalProducerGroup"); // 设置NameServer的地址 producer.setNamesrvAddr("localhost:9876"); // 启动生产者实例 producer.start(); // 发送消息 producer.send(new Message("TopicTest", "TagA", "Order001", "Payment message".getBytes(RemotingHelper.DEFAULT_CHARSET))); producer.send(new Message("TopicTest", "TagB", "Order002", "Shipping message".getBytes(RemotingHelper.DEFAULT_CHARSET))); producer.send(new Message("TopicTest", "TagA", "Order003", "Payment message".getBytes(RemotingHelper.DEFAULT_CHARSET))); // 关闭生产者实例 producer.shutdown(); } }

保证消息的顺序消费就必须保证以下两点

1、单线程消费:消息中间件可能会将一个topic下的消息分配给同一个消费者线程来处理,确保一个消费者线程只处理一个消息。这样可以确保消息的顺序消费,但会限制并发能力,因为所有的消息都被一个消费者消费

2、分区顺序消费:一些消息中间件支持分区,可以将消息分散到不同的分区中。在顺序消费的情况下,中间件可能会将同一个分区的消息发送给同一个消费者实例来处理,从而保证消息在分区内的顺序消费。但这种方式也会限制并发处理性能,因为消息被分配给不同的消费者实例进行顺序消费。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值