Advertisement

硬核干货:详解RocketMQ 顺序消费机制

阅读量:

顺序消息机制是指特定 Topic 下的消息按照先进先出原则依次发布和被消费, 即先前发布的消息将优先被处理, 而后续的消息将在之后被接收并处理。

顺序消息分为分区顺序消息全局顺序消息

1、分区顺序消息

在选定的特定 Topic 中,所有消息将基于 Sharding Key 分区。每个分区内部的消息将严格按照先进先出(FIFO)原则进行发布与消费。每个分区内部的消息保持有序。不同分区之间的消息顺序无须管束。

  • 适用场景:在高性能需求下,在同一个区块中遵循先进先出(FIFO)原则对消息进行发布与消费。
  • 示例:在线购物平台的交易流程中,在一个Shard块内通过指定的分区键(如OrderID)实现的消息处理逻辑包括但不限于创建新事务记录、完成支付操作以及处理退款请求等,并按时间顺序依次执行。

2、全局顺序消息

对于特定的主题T来说,在系统中每个消息都会依照严格的先进先出原则被发布与处理。

  • 适用场景:主要适用于系统性能要求不高的情况下,并且任何一条消息都需严格遵循 FIFO 原则来实现发布与消费的场景。
    • 示例:在证券处理中讨论以人民币兑美元为话题时,在同一价位下采用先报价者优先的方式可以获得资源,并且能够通过 FIFO 方式实现消息的整体顺序发送与接收。

全局顺序消息本质上是一种典型的分区顺序消息,在这种情况下每个 Topic 对应一个 Partition 因此全局顺序与分区顺序在实现原理上具有相似性

这种类型的消息通常包含多个分区信息。由于这种类型的消息通常包含多个分区信息,在并行处理能力更强的同时,并发性能也表现出色。

消息的顺序需要由两个阶段保证:

  • 消息发送

根据图所示,在系统架构中定义的各节点之间通过特定规则进行交互以保证系统的稳定运行

对于普通类型的消息,默认情况下可能会被分散至不同的队列中,在这种情况下各队列中的消息无法保证传递顺序。相反,在使用顺序模式时,RocketMQ能够实现具有相同Sharding Key属性(如同一订单号)的消息序列集中分配至同一个队列。

  • 消息消费

当消费者处理消息时

我们知道负载均衡服务是客户端的核心服务。在负载均衡阶段,并发消费与顺序消费并无显著差异。主要区别体现在:通过访问Borker资源来获取锁机制。

消费者基于分配的消息队列 messageQueue ,向 Borker 获取锁权限 ,当获得锁权限时会拉取消息 ,若未能获取,则定时任务每隔20秒将重新尝试

见上图,顺序消费核心流程如下:

1、 组装成消费对象

2、 将请求对象提交到消费线程池

在并发消费中,并非如此的是,在这里的一个消费请求涉及两个对象——过程快照(processQueue)和消息队列(messageQueue),而它们都不涉及对消息列表的任何操作。

3、 消费线程内,对消费队列加锁

4、 从消费快照中取得待消费的消息列表

在消息处理队列中,该功能模块初始化了一个名为 consumingMsgOrderlyTreeMap 的红黑树数据结构,用于暂存待处理的消息。

5、 执行消息监听器

易于理解地执行监听器逻辑,在消息快照中定义的消费锁 consumeLock 用于保护 MessageQueue 对象免受 Rebalance 线程的影响:确保不会被 Rebalance 线程从当前 MessageQueue 中删除。

6、 处理消费结果

消费成功时,首先计算需要提交的偏移量,然后更新本地消费进度。

消费失败时,分两种场景:

  • 如果当前已消耗次数低于最大重试阈值,则将待消费的消息暂存于 consumingMsgOrderlyTreeMap 对象中,并将其重新插入至消费快照中的红黑树 msgTreeMap 中;随后利用定时任务机制进行再尝试。
    • 如果当前已消耗次数达到或超过最大重试阈值,则需将失败信息投递至 Broker 端口;Broker 接收该信息后会归入死信队列处理;随后计算并提交必要的偏移量,并同步更新本地的消 费进度。

我们做一个关于顺序消费的总结:

  1. 顺序消费由两个关键环节协同运作完成(消息发送与消息消费),其底层架构基于 RocketMQ 的存储模型;
  2. 顺序消费服务采用三把锁机制确保数据安全;其数据将被单线程地进行消费处理;
  3. 当消费者进行扩容或重起操作时可能出现短暂乱序风险;仍需确保其业务逻辑保持一致性的要求。

全部评论 (0)

还没有任何评论哟~