1.RocketMQ的四种消息类型?
RocketMQ支持四种消息类型:普通消息、顺序消息、延迟消息和事务消息。
- 普通消息:无特殊顺序或延迟要求的消息。
- 顺序消息:保证消息按发送顺序被消费。
- 延迟消息:消息发送后不立即投递,而是延迟指定时间后再消费。
- 事务消息:支持分布式事务,通过两阶段提交保证消息发送与本地事务的一致性。
2.在RocketMQ中消息存储的核心是什么?
RocketMQ的消息存储核心组件是 CommitLog 和 ConsumeQueue。
- CommitLog:存储所有消息的物理文件,消息以顺序追加方式写入。
- ConsumeQueue:消费队列,记录消息在CommitLog中的偏移量,供消费者快速定位消息。
3.RocketMQ中的NameServer主要负责什么?
NameServer是RocketMQ的路由注册中心,主要职责包括:
- Broker管理:接收Broker的心跳上报,维护Broker的动态路由信息。
- 路由发现:为Producer和Consumer提供Topic的路由信息(如Broker地址)。
- 轻量级设计:无状态,可横向扩展,支持动态更新路由信息。
4.RocketMQ的Broker组件支持哪些功能?
Broker是RocketMQ的核心存储和转发组件,支持以下功能:
- 消息存储:将消息持久化到磁盘(CommitLog和ConsumeQueue)。
- 消息转发:根据路由规则将消息转发给消费者。
- 消息查询:支持按消息ID或Key查询消息。
- 主从同步:通过主从复制实现高可用性。
- 流量控制:根据负载动态调整消息发送速率。
5.RocketMQ架构图
主要由以下几个核心组件构成,每个组件都承担着特定的功能,共同协作以实现高效、可靠的消息传递。

NameServer
NameServer 是一个无状态的服务器,角色类似于 Kafka使用的 Zookeeper,但比 Zookeeper 更轻量。
特点:每个 NameServer 结点之间是相互独立,彼此没有任何信息交互。 Nameserver 被设计成几乎是无状态的,通过部署多个结点来标识自己是一个伪集群,Producer 在发送消息前从 NameServer 中获取 Topic 的路由信息也就是发往哪个 Broker,Consumer 也会定时从 NameServer 获取 Topic 的路由信息,Broker 在启动时会向 NameServer 注册,并定时进行心跳连接,且定时同步维护的 Topic 到 NameServer。
功能主要有两个:
- 1、和Broker结点保持长连接。
- 2、维护Topic的路由信息。
Broker
消息存储和中转角色,负责存储和转发消息。
Broker 内部维护着一个个 Consumer Queue,用来存储消息的索引,真正存储消息的地方是 CommitLog(日志文件)。
单个 Broker 与所有的 Nameserver 保持着长连接和心跳,并会定时将 Topic 信息同步到 NameServer,和 NameServer 的通信底层是通过 Netty 实现的。
Producer
消息生产者,业务端负责发送消息,由用户自行实现和分布式部署。 Producer由用户进行分布式部署,消息由Producer通过多种负载均衡模式发送到Broker集群,发送低延时,支持快速失败。
RocketMQ 提供了三种方式发送消息
同步、异步和单向
- 同步发送:同步发送指消息发送方发出数据后会在收到接收方发回响应之后才发下一个数据包。一般用于重要通知消息,例如重要通知邮件、营销短信。
- 异步发送:异步发送指发送方发出数据后,不等接收方发回响应,接着发送下个数据包,一般用于可能链路耗时较长而对响应时间敏感的业务场景,例如用户视频上传后通知启动转码服务。
- 单向发送:单向发送是指只负责发送消息而不等待服务器回应且没有回调函数触发,适用于某些耗时非常短但对可靠性要求并不高的场景,例如日志收集。
Consumer
消息消费者,负责消费消息,一般是后台系统负责异步消费。
Consumer也由用户部署,支持PUSH和PULL两种消费模式,支持集群消费和广播消费,提供实时的消息订阅机制。
- Pull:拉取型消费者(Pull Consumer)主动从消息服务器拉取信息,只要批量拉取到消息,用户应用就会启动消费>过程,所以 Pull 称为主动消费型。
- Push:推送型消费者(Push Consumer)封装了消息的拉取、消费进度和其他的内部维护工作,将消息到达时执行的回调接口留给用户应用程序来实现。所以 Push 称为被动消费类型,但其实从实现上看还是从消息服务器中拉取消息,不同于 Pull 的是 Push 首先要注册消费监听器,当监听器处触发后才开始消费消息。
6.在RocketMQ中,支持的消息消费的模式有哪些?
RocketMQ支持两种消息消费模式:
- 集群消费(Clustering):同一Consumer Group内的消费者共享消息,每条消息只被一个消费者消费。
- 广播消费(Broadcasting):同一Consumer Group内的每个消费者都会收到所有消息。
7.在RocketMQ中,Producer充当的角色?
-
创建消息:
- Producer可以创建包含特定主题(Topic)、标签(Tag,可选)和消息体(Body)的消息对象。
-
发送消息:
- Producer可以将创建好的消息发送到指定的Topic。发送方式可以是同步、异步或单向(One-way)。
- 同步发送:Producer发送消息后,会等待Broker的确认响应。
- 异步发送:Producer发送消息后,不需要等待Broker的响应,可以通过回调函数处理发送结果。
- 单向发送:Producer只负责发送消息,不关心Broker是否收到或处理该消息。
-
选择消息队列:
- 在发送消息时,Producer可以根据一定的策略(如轮询、随机、哈希等)选择将消息发送到Topic下的哪个消息队列(Message Queue)。
-
事务消息(可选) :
- Producer可以发送事务消息,这是一种支持分布式事务的消息类型。在事务消息中,Producer可以确保消息的发送和本地事务的执行要么都成功,要么都失败。
-
批量发送消息:
- Producer可以将多条消息批量发送到Broker,以减少网络传输的开销和提高发送效率。
-
设置消息属性:
- Producer可以为消息设置一些属性,如延迟级别(Delay Level)、重试次数等,以满足特定的业务需求。
-
关闭Producer:
- 在不再需要发送消息时,Producer可以关闭以释放资源。
8.如何保证消息的可用性/可靠性/不丢失呢?
消息可能在哪些阶段丢失呢?可能会在这三个阶段发生丢失:生产阶段、存储阶段、消费阶段。
所以要从这三个阶段考虑:
生产
在生产阶段,主要通过请求确认机制,来保证消息的可靠传递。
- 1、同步发送的时候,要注意处理响应结果和异常。如果返回响应OK,表示消息成功发送到了Broker,如果响应失败,或者发生其它异常,都应该重试。
- 2、异步发送的时候,应该在回调方法里检查,如果发送失败或者异常,都应该进行重试。
- 3、如果发生超时的情况,也可以通过查询日志的API,来检查是否在Broker存储成功。
存储
存储阶段,可以通过配置可靠性优先的 Broker 参数来避免因为宕机丢消息,简单说就是可靠性优先的场景都应该使用同步。
- 1、消息只要持久化到CommitLog(日志文件)中,即使Broker宕机,未消费的消息也能重新恢复再消费。
- 2、Broker的刷盘机制:同步刷盘和异步刷盘,不管哪种刷盘都可以保证消息一定存储在pagecache中(内存中),但是同步刷盘更可靠,它是Producer发送消息后等数据持久化到磁盘之后再返回响应给Producer。
- 3、Broker通过主从模式来保证高可用,Broker支持Master和Slave同步复制、Master和Slave异步复制模式,生产者的消息都是发送给Master,但是消费既可以从Master消费,也可以从Slave消费。同步复制模式可以保证即使Master宕机,消息肯定在Slave中有备份,保证了消息不会丢失。

消费
从Consumer角度分析,如何保证消息被成功消费?
Consumer保证消息成功消费的关键在于确认的时机,不要在收到消息后就立即发送消费确认,而是应该在执行完所有消费业务逻辑之后,再发送消费确认。因为消息队列维护了消费的位置,逻辑执行失败了,没有确认,再去队列拉取消息,就还是之前的一条。
9.RocketMQ如何避免消息重复消费的问题呢?
对分布式消息队列来说,同时做到确保一定投递和不重复投递是很难的,就是所谓的"有且仅有一次" 。RocketMQ择了确保一定投递,保证消息不丢失,但有可能造成消息重复。
处理消息重复问题,主要有业务端自己保证,主要的方式有两种:业务幂等和消息去重。
-
业务幂等:第一种是保证消费逻辑的幂等性,也就是多次调用和一次调用的效果是一样的。这样一来,不管消息消费多少次,对业务都没有影响。
-
消息去重:第二种是业务端,对重复的消息就不再消费了。这种方法,需要保证每条消息都有一个唯一的编号,通常是业务相关的,比如订单号,消费的记录需要落库,而且需要保证和消息确认这一步的原子性。
具体做法是可以建立一个消费记录表,拿到这个消息做数据库的insert操作。给这个消息做一个唯一主键(primary key)或者唯一约束,那么就算出现重复消费的情况,就会导致主键冲突,那么就不再处理这条消息。
10.怎么处理消息积压?
发生了消息积压,这时候就得想办法赶紧把积压的消息消费完,就得考虑提高消费能力,一般有两种办法:

- 消费者扩容:如果当前Topic的Message Queue的数量大于消费者数量,就可以对消费者进行扩容,增加消费者,来提高消费能力,尽快把积压的消息消费玩。
- 消息迁移Queue扩容:如果当前Topic的Message Queue的数量小于或者等于消费者数量,这种情况,再扩容消费者就没什么用,就得考虑扩容Message Queue。
可以新建一个临时的Topic,临时的Topic多设置一些Message Queue,然后先用一些消费者把消费的数据丢到临时的Topic,因为不用业务处理,只是转发一下消息,还是很快的。接下来用扩容的消费者去消费新的Topic里的数据,消费完了之后,恢复原状。

11.顺序消息如何实现?
顺序消息通过以下机制保证顺序性:
- 顺序发送:Producer按顺序发送消息到同一Queue。
- 顺序存储:Broker将同一Queue的消息顺序写入CommitLog。
- 顺序消费:Consumer从同一Queue按顺序拉取并消费消息。
- 单线程消费:每个Queue对应一个消费线程,避免并发导致的乱序
顺序消息是指消息的消费顺序和产生顺序相同,在有些业务逻辑下,必须保证顺序,比如订单的生成、付款、发货,这个消息必须按顺序处理才行。
顺序消息分为全局顺序消息和部分顺序消息:
全局顺序消息指某个 Topic 下的所有消息都要保证顺序; 部分顺序消息只要保证每一组消息被顺序消费即可,比如订单消息,只要保证同一个订单 ID 个消息能按顺序消费即可。
部分顺序消息
部分顺序消息相对比较好实现,生产端需要做到把同 ID 的消息发送到同一个 Message Queue ;在消费过程中,要做到从同一个Message Queue读取的消息顺序处理------消费端不能并发处理顺序消息,这样才能达到部分有序。
发送端使用 MessageQueueSelector 类来控制 把消息发往哪个 Message Queue 。
消费端通过使用 MessageListenerOrderly 来解决单 Message Queue 的消息被并发处理的问题。
全局顺序消息
RocketMQ 默认情况下不保证顺序,比如创建一个 Topic ,默认八个写队列,八个读队列,这时候一条消息可能被写入任意一个队列里;在数据的读取过程中,可能有多个 Consumer ,每个 Consumer 也可能启动多个线程并行处理,所以消息被哪个 Consumer 消费,被消费的顺序和写人的顺序是否一致是不确定的。
要保证全局顺序消息, 需要先把 Topic 的读写队列数设置为 一,然后Producer Consumer 的并发设置,也要是一。简单来说,为了保证整个 Topic全局消息有序,只能消除所有的并发处理,各部分都设置成单线程处理 ,这时候就完全牺牲RocketMQ的高并发、高吞吐的特性了。
12.如何实现消息过滤?
有两种方案:
- 一种是在 Broker 端按照 Consumer 的去重逻辑进行过滤,
这样做的好处是避免了无用的消息传输到 Consumer 端,缺点是加重了 Broker 的负担,实现起来相对复杂。 - 另一种是在 Consumer 端过滤,比如按照消息设置的 tag 去重,这样的好处是实现起来简单,缺点是有大量无用的消息到达了 Consumer 端只能丢弃不处理。 一般采用Cosumer端过滤,如果希望提高吞吐量,可以采用Broker过滤。
对消息的过滤有三种方式:

- 根据Tag过滤:这是最常见的一种,用起来高效简单
js
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("CID_EXAMPLE");
consumer.subscribe("TOPIC", "TAGA || TAGB || TAGC");
- SQL表达式过滤(需Broker配置enablePropertyFilter=true):SQL表达式过滤更加灵活
js
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");
// 只有订阅的消息有这个属性a, a >=0 and a <= 3
consumer.subscribe("TopicTest", MessageSelector.bySql("a between 0 and 3");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
- Filter Server 方式:最灵活,也是最复杂的一种方式,允许用户自定义函数进行过滤
13.延时消息?
电商的订单超时自动取消,就是一个典型的利用延时消息的例子,用户提交了一个订单,就可以发送一个延时消息,1h后去检查这个订单的状态,如果还是未付款就取消订单释放库存。
RocketMQ是支持延时消息的,只需要在生产消息的时候设置消息的延时级别:
js
// 实例化一个生产者来产生延时消息
DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
// 启动生产者
producer.start();
int totalMessagesToSend = 100;
for (int i = 0; i < totalMessagesToSend; i++) {
Message message = new Message("TestTopic", ("Hello scheduled message " + i).getBytes());
// 设置延时等级3,这个消息将在10s之后发送(现在只支持固定的几个时间,详看delayTimeLevel)
message.setDelayTimeLevel(3);
// 发送消息
producer.send(message);
}
但是目前RocketMQ支持的延时级别是有限的:
"1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"
18.RocketMQ怎么实现延时消息的原理?
临时存储+定时任务。
Broker收到延时消息了,会先发送到主题(SCHEDULE_TOPIC_XXXX)的相应时间段的Message Queue中,然后通过一个定时任务轮询这些队列,到期后,把消息投递到目标Topic的队列中,然后消费者就可以正常消费这些消息。

19.怎么实现分布式消息事务的?半消息?
半消息:是指暂时还不能被 Consumer 消费的消息,Producer 成功发送到 Broker 端的消息,但是此消息被标记为 "暂不可投递" 状态,只有等 Producer 端执行完本地事务后经过二次确认了之后,Consumer 才能消费此条消息。
依赖半消息,可以实现分布式消息事务,其中的关键在于二次确认以及消息回查:

- 1、Producer 向 broker 发送半消息
- 2、Producer 端收到响应,消息发送成功,此时消息是半消息,标记为 "不可投递" 状态,Consumer 消费不了。
- 3、Producer 端执行本地事务。
- 4、正常情况本地事务执行完成,Producer 向 Broker 发送 Commit/Rollback,如果是 Commit,Broker 端将半消息标记为正常消息,Consumer 可以消费,如果是 Rollback,Broker 丢弃此消息。
- 5、异常情况,Broker 端迟迟等不到二次确认。在一定时间后,会查询所有的半消息,然后到 Producer 端查询半消息的执行情况。
- 6、Producer 端查询本地事务的状态
- 7、根据事务的状态提交 commit/rollback 到 broker 端。(5,6,7 是消息回查)
- 8、消费者段消费到消息之后,执行本地事务,执行本地事务。
30.push模式与pull模式的区别
- 概念上的区别
| 特性 | Pull(拉取)模式 | Push(推送)模式 |
|---|---|---|
| 消息获取方式 | 消费者(Consumer)主动调用 API 从 Broker 拉取消息。 | 消费者看似被动接收,由 RocketMQ 客户端内部机制自动完成消息的获取与分发。 |
| 控制权 | 完全掌握在应用手中,应用自行决定何时拉取、拉取多少消息。 | 由 RocketMQ 客户端库负责管理消息拉取和分发给应用。 |
| 底层实现 | 消费者直接执行拉取逻辑。 | 底层依然是 Pull 机制,但客户端框架对其进行了封装。 |
2.对开发者的影响与适用场景
| 特性 | Pull(拉取)模式 | Push(推送)模式 |
|---|---|---|
| 开发复杂度 | 较高,需要开发者自行实现消息拉取、定时、流量控制等逻辑。 | 较低,开发者只需关注实现消息处理的业务逻辑(注册一个监听器)。 |
| 灵活性/控制力 | 高,可以根据业务需求精细地控制消费速率、拉取间隔、特定时间点启动消费等。 | 一般,灵活性的定制受到框架约束,但对大多数场景足够使用。 |
| 适用场景 | 适用于需要对消息处理有精细控制的场景,例如需要严格控制流量、自定义拉取策略等。 | 适用于大多数消息消费场景,希望简化应用逻辑,让框架自动处理消息获取和调度。 |
| 主流使用 | 相对少见,除非有特殊定制需求。 | RocketMQ 推荐和最常用的模式。 |