详细介绍:RocketMQ
RocketMQ
RocketMQ的自我介绍
官网地址:https://rocketmq.apache.org/zh/docs/
使用MQ的场景:解耦、异步、削峰
具有的特性:
- 云原生:生于云,长于云,无限弹性扩缩,K8s 友好
- 高吞吐:万亿级吞吐保证,同时满足微服务与大材料场景
- 流处理:提供轻量、高扩展、高性能和丰富功能的流计算引擎
- 金融级:金融级的稳定性,广泛用于交易核心链路
- 架构极简:零外部依赖,Shared-nothing 架构
- 生态友好:无缝对接微服务、实时计算、数据湖等周边生态
跟其他MQ最大对比:Java生态
部署模型图:
架构分为四大模块:生产者、broker、NameServer、消费者
数据流转:
- 业务消息按照要求封装成message,并发送至RocketMQ服务端
- 消息按照到达RocketMQ 服务端的顺序存储到主题的指定队列中。
- 消费者按照指定的订阅关系从RocketMQ 服务端中获取消息并消费。
生产者
在消息生产者中,能够定义如下传输行为:
- 发送方式:生产者可通过API接口设置消息发送的方式。RocketMQ 支持同步传输和异步传输。
- 批量发送:生产者可通过API接口设置消息批量传输的方式。例如,批量发送的消息条数或消息大小。
- 事务行为:RocketMQ 支持事务消息,对于事务消息需要生产者配合进行事务检查等行为保障事务的最终一致性。
事务消息:
- 生产者将消息发送至Apache RocketMQ服务端。
- Apache RocketMQ服务端将消息持久化成功之后,向生产者返回Ack确认消息已经发送成功,此时消息被标记为"暂不能投递",这种状态下的消息即为半事务消息(处于 “待确认” 状态的特殊消息)。
- 生产者开始执行本地事务逻辑。
- 生产者根据本地事务执行结果向服务端提交二次确认结果(Commit或是Rollback),服务端收到确认结果后处理逻辑如下:
- 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者。
- 二次确认结果为Rollback:服务端将回滚事务,不会将半事务消息投递给消费者。
- 在断网或者是生产者应用重启的特殊情况下,若服务端未收到发送者提交的二次确认结果,或服务端收到的二次确认结果为Unknown未知状态,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查。 (此时用到的本地消息表)
- 生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
- 生产者根据检查到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。
顺序消息
生产顺序性
消息生产的顺序性:
- 单一生产者:消息生产的顺序性仅支持单一生产者,不同生产者分布在不同的平台,即使设置相同的消息组,不同生产者之间产生的消息也无法判定其先后顺序。
- 串行发送:Apache RocketMQ 生产者客户端支持多线程安全访问,但如果生产者应用多线程并行发送,则不同线程间产生的消息将无法判定其先后顺序。
服务端顺序存储逻辑如下:
- 相同消息组的消息按照先后顺序被存储在同一个队列。
- 不同消息组的消息可以混合在同一个队列中,且不保证连续。
消费顺序性
消息消费的顺序性:
- 投递顺序
Apache RocketMQ 通过客户端SDK和服务端通信协议保障消息按照服务端存储顺序投递,但业务方消费消息时需要严格按照接收—处理—应答的语义处理消息,避免因异步处理导致消息乱序。
备注:消费者类型为PushConsumer时, Apache RocketMQ 保证消息按照存储顺序一条一条投递给消费者,若消费者类型为SimpleConsumer,则消费者有可能一次拉取多条消息。此时,消息消费的顺序性需要由业务方自行保证。
- 有限重试
Apache RocketMQ 顺序消息投递仅在重试次数限定范围内,即一条消息如果一直重试失败,超过最大重试次数后将不再重试,跳过这条消息消费,不会一直阻塞后续消息处理。
对于需要严格保证消费顺序的场景,请务设置合理的重试次数,避免参数不合理导致消息乱序。
定时/延时消息
生产者会在消息属性中设置DELAY标记,并将消息的目标主题和队列存入消息属性。此时消息实际被发送到系统内置的延时主题SCHEDULE_TOPIC_XXX,而非业务主题。定义了18个延时等级,对应不同的延时时间,每个延时等级对应SCHEDULE_TOPIC_XXX下的一个队列(Queue)
- 暂存到延时队列:像普通消息一样写入 CommitLog 并建立 ConsumeQueue 索引,但此时消费者无法直接消费
- 定时扫描到期消息:Broker 启动时会为每个延时等级的队列创建一个 定时任务(ScheduleMessageService),定期(默认每 100ms)扫描队列中消息的到期状态:任务根据消息的存储时间(storeTimestamp)和延时等级计算 到期时间(storeTimestamp + 延时时间)。若当前时间 ≥ 到期时间,则判定消息已到期。
- 到期消息重投:对于到期的消息,Broker 会执行以下操控:
清除消息的 DELAY 标记,恢复其原始主题(REAL_TOPIC)和队列(REAL_QUEUE_ID)。将消息重新写入 CommitLog(此时作为普通消息存储到业务主题对应的队列)。消息进入业务主题的 ConsumeQueue 后,消费者即可正常消费。
服务端(broker)
同步刷盘
异步刷盘
CommitLog
物理存储档案,顺序读写,只允许追加,不允许修改。记录的offset偏移量
IndexFile
RocketMQ 为 消息 Key 迅速查询 设计的哈希索引文件,用于利用消息的 Key 或 UniqueKey 快速定位消息在 CommitLog 中的位置,提升查询效率。
消费者
在实际使用场景中,PullConsumer 仅推荐在流处理框架中集成使用,大多数消息收发场景使用 PushConsumer 和 SimpleConsumer 就能够满足需求。
先需要明确一个关键事实:RocketMQ 底层仅拥护 “拉取” 机制—— 消费者必须主动从 Broker 拉取消息,不存在 Broker 主动将消息 “推” 给消费者的原生能力。
伪Push操控:所谓的 “Push 模式”,本质是 RocketMQ 客户端(Consumer)封装了 “拉取 - 等待 - 再拉取” 的循环逻辑,模拟出 “ Broker 主动推送” 的效果;而 “Pull 模式” 则是将拉取的控制权完全交给开发者。
PushConsumer
客户端封装拉取逻辑:拉取到消息后立即回调业务处理;若拉取不到则长轮询等待(默认 30s),Broker 有消息时会唤醒客户端。
SimpleConsumer
为应对 Pull 模式的复杂性,RocketMQ 5.x 推出了 SimpleConsumer 模式,它是一种 “简化的拉取模式”:
客户端仍需主动调用拉取 API,但框架会自动处理 offset 提交、负载均衡、长轮询等待 等细节;
兼顾了 Pull 模式的灵活性(可控制拉取时机)和 Push 模式的易用性(无需处理底层细节),适合对消费时机有一定控制需求的场景。
SimpleConsumer适用于以下场景:
- 通过消息处理时长不可控:如果消息处理时长无法预估,经常有长时间耗时的消息处理情况。建议使用SimpleConsumer消费类型,能够在消费时自定义消息的预估处理时长,若实际业务中预估的消息处理时长不符合预期,也许可通过接口提前修改。
- 需要异步化、批量消费等高级定制场景:SimpleConsumer在SDK内部没有复杂的线程封装,完全由业务逻辑自由定制,可以完成异步分发、批量消费等高级定制场景。
- 由业务逻辑主动调用接口获取消息,因此可以自由调整获取消息的频率,自定义控制消费速率。就是需要自定义消费速率:SimpleConsumer
PullConsumer
仅推荐在流处理框架场景下集成使用
默认参数配置
消息大小:默认值:不超过4 MB。不涉及消息压缩,仅计算消息体body的大小。取值范围:建议不超过4 MB。
事务和定时或延时消息:64 KB。
消息发送重试次数:默认值:3次。取值范围:无限制。
消息消费重试次数:默认值:16次。
事务异常检查间隔:默认值:60秒。
PushConsumer本地缓存:默认值:最大缓存数量:1024条。最大缓存大小:64 M。取值范围:支持用户自定义设置,无限制。
PushConsumer重试间隔时长:默认值:非顺序性投递:间隔时间阶梯变化,具体取值,请参见PushConsumer消费重试策略。顺序性投递:3000毫秒。
PushConsumer消费并发度:默认值:20个线程。
获取消息最大批次:默认值:32条。
面试常问的困难
可靠性
生产端依据确认与重试确保消息送达 Broker;
Broker 通过持久化、主从复制确保消息不丢失;
消费端通过确认、重试、死信队列确保消息被正确处理。
顺序性
路由控制:通过 Key 或队列选择器,将同一业务流的消息路由到固定队列。
存储有序:队列内消息按发送顺序追加写入,物理上保证 FIFO。
消费有序:消费者单线程处理单个队列的消息,串行执行并原子提交进度。
事务性
半事务消息确保消息先送达 Broker,避免本地事务成功但消息丢失。
事务监听器将本地业务与事务状态绑定,通过数据库事务保证原子性。
定时回查机制解决网络异常等导致的状态未知障碍,确保事务最终闭环。
幂等性
RocketMQ 消息幂等性的核心实现依赖 业务方自身的去重机制,而非中间件原生保证:
唯一标识:优先使用业务 Key(如订单 ID),其次利用 RocketMQ 生成的 msgId。
去重手段:根据并发量选择数据库唯一索引(可靠性高)或分布式缓存(性能高)。
原子性:确保 “判断重复” 与 “处理业务” 的原子性,避免并发场景下的重复处理。
流速控制
- 生产者流速控制:
- 限流参数设置:生产者可以通过 setSendMsgTimeout 设置发送超时时间,避免长时间阻塞;依据 setMaxMessageSize 限制单条消息大小,防止超大消息占用过多资源。
- 流量控制:在高并发场景下,生产者可能通过业务层实现令牌桶或漏桶算法,主动控制发送速率。
- 消费者流速控制:
- 消费线程池控制:通过 setConsumeThreadMin 和 setConsumeThreadMax 控制消费线程数量,间接限制并发消费能力。
- 批量消费限制:通过 setConsumeMessageBatchMaxSize 设置每次批量消费的消息数量。
- 流控阈值:当消息堆积过多时,RocketMQ 会触发流控,降低推送速度,避免消费者过载。
- broker 端全局流控
- 队列流量控制:Broker 会监控每个队列的消息堆积情况,当超过阈值时,会限制生产者的发送速度。
- 磁盘和内存保护:当 Broker 磁盘空间不足或内存占用过高时,会触发全局流控,拒绝部分发送请求,直到资源恢复正常。
- 基于消息重试的间接流控
- 当消费者处理消息失败时,RocketMQ 会按照一定策略进行重试(可通过 setRetryTimesWhenSendFailed 配置)。重试机制间接起到了流速控制作用,避免错误消息持续占用资源。