RocketMQ保证消息有序性

引言

在某些业务场景中,MQ需要保证消息的顺序性,比如支付订单应该在创建订单之后进行

如果不使用保证顺序的手段,由于多队列、网络等因素可能会导致先处理支付订单的消息再处理创建订单的消息,这样就会导致处理失败

为了避免这样的情况发生,使用MQ时有必要保证消息的顺序性,在RocketMQ中通常使用顺序发送消息和顺序消费消息来保证消息的顺序性

生产者端保证消息有序

当队列全局只有一个时,消息全局有序,此时只需要确保为单个生产者发送(多个生产者同时发送无法预估消息到达的顺序)

或者先生产创建订单的消息再生产支付订单的消息(确保消息不丢)由于全局有序只能有一个队列,队列的压力过大,所以不经常使用

更通用的做法是使用队列有序:在发送消息时通过一定的路由算法将需要有序的消息分发到同一个队列中,使用相同的队列保证有序性

顺序消息分类

RocketMQ 提供了两种顺序消息,即全局顺序消息和分区顺序消息。

  • 全局顺序消息:指某个 Topic 下的所有消息都要保证顺序。在这种情况下,Topic 内部只能有一个队列,生产者将消息顺序发送到这个唯一的队列中。因为队列本身是 FIFO(先进先出)的数据结构,所以进入队列的消息天然有序。不过,由于只有一个队列,会导致并发度很低,吞吐量也会受到限制,因此全局顺序消息的使用场景相对较少。

  • 分区顺序消息:指在一个分区(队列)内的消息有序,不同分区之间的消息可以无序。这是更常见的使用方式,既保证了一定程度的顺序性,又能通过多个分区提高系统的并发能力和吞吐量。

实现分区顺序消息的发送

为了实现分区顺序消息的发送,生产者在发送消息时需要指定消息的路由规则,确保同一业务逻辑下的消息被发送到同一个队列中。例如,在电商系统中,一个订单的不同状态变更消息需要保证顺序,那么可以使用订单 ID 作为消息的路由键。

private SendResult sendSelectImpl(
    Message msg,
### 确保 RocketMQ 消息顺序性的方法 #### 生产端配置 为了确保消息按照预期顺序被发送,在生产者侧需采用特定策略来控制消息进入哪个队列。具体来说,当向指定主题(Topic)发布消息时,应始终将具有相同键值的消息路由至同一队列内[^3]。 ```java MessageQueueSelector selector = (mqs, msg, arg) -> { Integer queueId = (Integer)arg; int index = queueId % mqs.size(); return mqs.get(index); }; producer.send(msg, selector, queueId); // 使用自定义的选择器并传递参数用于决定目标队列 ``` 上述代码展示了如何利用 `MessageQueueSelector` 接口来自定义选择逻辑,从而保证同类消息总是落入相同的队列中。 #### 消费端设置 消费者方面则要遵循单线程模式逐条处理来自同一个队列内的所有记录,以此维持接收次序不变。对于每一个订阅的主题而言,可以通过设定消费实例的数量不超过该主题下物理分区数目来达成此目的;另外还需开启同步提交确认机制以防止因网络波动造成的数据丢失或重复读取现象发生[^1]。 ```properties # 配置文件示例 consumer.group.id=my_group_name consume.message.batch.max.size=1 # 设置每次只拉取一条消息进行处理 concurrent.consumers=topic_queue_num # 控制并发消费者的数量等于主题下的队列数 ``` 以上配置项能够帮助应用程序更稳定地维护消息间的相对位置关系,进而满足业务上关于数据流转的一致性需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值