当前位置: 首页 > news >正文

rocketmq 单消费者多线程消费是如何保证分区内的顺序消息严格按照 FIFO 顺序消费的?

rocketmq 单消费者多线程消费是如何保证分区内的顺序消息严格按照 FIFO 顺序消费的?

想要实现真正的顺序消费,必须同时实现生产顺序性和消费顺序性。

生产顺序性:采用单一生产者单线程串行生产消息。或者保证同一个分区键的消息能交由同一个生产者串行发送。

消费顺序性:保证同一个分区键的消息按照投递顺序串行消费。

生产顺序性比较好实现,消费顺序性如果采用单线程消费也好实现,但是消费的速度太慢了,很容易导致消息积压。rocketmq 默认单个消费者是多线程消费的,我之前一直好奇多线程消费是如何保证同一个分区键的消息按照投递顺序串行消费的,最近研究了一下。

这里基于 rocketmq 4.x 版本说明,rocketmq消费模式时分为并发消费和顺序消费,启动消费者时需要设置MessageListener实现具体的消费逻辑,并发消费使用MessageListenerConcurrently,没有任何顺序保证;顺序消费使用MessageListenerOrderly,能保证同一个分区键的消息按照投递顺序串行消费,默认的消费线程数都为 20。

消息模式有两种,广播模式下消息会被广播给消费组内的每一个消费者,集群模式下 rocketmq 能保证一个分区(rocketmq 称为队列)的消息只会被同一消费组内的一个消费者消费。

使用DefaultMQPushConsumer推模式测试,客户端从 MQ 中获取消息后,会将消息提交到线程池中执行。

topic 的默认分区数(队列数)是 8,queueId 是 0 到 7。

从 mq 获取消息

pullResult是消费组从 mq 获取消息的请求,下图中是消费者组 order_c2 从主题 topic_order2 的队列 1 偏移量是 201 的地方获取消息,获取成功后 338 行先将获取的消息列表放入processQueue中,然后调用DefaultMQPushConsumerImpl.this.consumeMessageService.submitConsumeRequest向线程池提交任务。

并发消费

并发消费由org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService#submitConsumeRequest方法提交任务,任务对象为org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService.ConsumeRequest,构造方法有三个参数new ConsumeRequest(msgs, processQueue, messageQueue)

以下是ConsumeRequest#run方法的实现,被选中的status = listener.consumeMessage(Collections.unmodifiableList(msgs), context);就是调用MessageListenerConcurrently#consumeMessage方法执行自定义的消费逻辑,前面没有任何的加锁或其他同步代码,所以没有任何顺序保证。消费完构造方法传入的msgs就结束了。

顺序消费

顺序消费由org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService#submitConsumeRequest方法提交任务,任务对象为org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService.ConsumeRequest,构造方法只有两个参数new ConsumeRequest(processQueue, messageQueue)

messageQueueprocessQueue的作用、区别:

messageQueue只有topicbrokerNamequeueId三个字段,是 mq 分区(队列)的一个简单代表。

processQueue中维护了messageQueue所代表的分区(队列)的待消费的消息、offset、数量等详细的信息。

processQueue使用TreeMap维护消息,key 为 offset,value 为MessageExt,在takeMessages时能保证按照 offset 从小到大顺序获取。

在 433 行对messageQueue加了synchronized锁,messageQueue代表的是主题 topic_order2 的队列 1。

437 行 for 循环一直消费,直到消费失败或者没有可消费的消息了。如果因为消费失败而退出循序,在下一次执行run方法会自动重试失败的消息。

466 行List<MessageExt> msgs = this.processQueue.takeMessages(consumeBatchSize)获取消息。

490 到 580 行,获取processQueueConsumeLock加锁并消费、解锁。

总结:顺序消费利用messageQueueLockprocessQueueConsumeLock两个锁将同一 topic 的同一 queue 的消息的消费给串行化了。

由于 queue 的顺序消费是串行化的,所以在创建 topic 时一个尽量将分区(队列)数设置的大一点,否则容易消息积压。

http://www.jsqmd.com/news/1155520/

相关文章:

  • OpenClaw 可视化部署完整实操,简化重复办公流程
  • 2026 年海宁汽车维修保养怎么选?天宇汽修13819022727甄选指南 - GrowUME
  • C盘空间不够怎么清理?先分清垃圾、缓存和大文件三类再动手
  • STC15单片机声光报警器实战:PCF8591+AT24C02实现光强阈值掉电保存
  • Draw.io UML 2.5 类图实战:3分钟完成Python类结构可视化(附模板)
  • 基于TPD2015FN与STM32的高性能负载控制系统设计
  • 亨得利官方名表服务中心|最新官方热线及详细地址权威信息公示(2026年7月最新) - 亨得利钟表维修中心
  • Python图像元数据处理:pyexiv2库安装、使用与实战指南
  • 3.3V 单片机系统电源切换电路:4种方案压降与成本实测对比
  • 武汉市汉阳区亨得利官方钟表服务中心电话公示(2026年7月最新) - 亨得利钟表维修中心
  • 无锡剥线机厂家怎么选,这几个实用方法帮你避坑
  • Claude Code 是什么?深度解析社区驱动的 Claude CLI 工具链
  • 扬州2026全屋定制,江都业主私藏的性价比之选 - 设计本
  • 【纪实】古法中医融合现代微创|探访湘乡起蛟中医医院两大核心特色科室
  • 李华渊:从科研试剂到AI中医,一位跨界者的二十年“骑士之旅”
  • NCP1654 PFC控制器实战:CCM模式65kHz升压电路,功率因数提升至0.99
  • 西安主流高考全日制补习学校有哪些?正规机构梯队排名+择校攻略 - 资讯焦点
  • 2026覆盖拱墅上城全域上门!逸程奢侈品回收估价不满意无需成交 - 逸程奢侈品回收中心
  • 2U机身藏超强算力!云尖信息R6260 F6国产异构算力服务器
  • 行业视角深圳翻译公司推荐:从专利精准到展会高效,科技型企业选型指南 - 信息热点
  • 实测东莞南城黄金回收临街门店真实探店记录 - 融媒生活
  • 如何快速掌握BiliTools哔哩哔哩工具箱:跨平台B站资源下载终极指南
  • STM32H750与TB6593FNG实现高精度直流电机控制
  • 3种主流车载总线技术对比:CAN-FD vs FlexRay vs 车载以太网,成本与性能实测分析
  • 今日日常3
  • WSL2运行WorldVLA避坑指南:CUDA+OpenGL环境全链路配置
  • 终极黑苹果安装指南:5步快速配置OpenCore让PC运行macOS系统
  • LIN总线 2.2A协议:基于STM32 UART实现20kbps车身控制从机节点
  • KES数据库医疗信创实战:含架构+代码实现
  • 从Web渗透到内网横向:Docker逃逸与容器安全实战剖析