mq和rocketmq
发送同步消息如出现了异常,我们怎么进行消息可靠性保障
你在开发中怎么使用的MQ
你在项目中的哪些场景使用到了MQ
保证顺序性的第一个前提:将一组要保障顺序的消息放到同一个队列
保证顺序性第二个前提:使用单线程消费
MQ面试题
1. RocketMQ 的作用?
什么是MQ
MQ就是一个消息的中间件, 能够实现消息的发送和接收, 我们在开发中经常会使用MQ实现一个异步的调用, 还有一些延迟的调用
1解耦:拆分依赖系统,如订单系统完成后,通过 MQ 通知短信服务,无需直接调用。
2削峰填谷:应对高并发场景(如电商秒杀),前端请求先写入 MQ,后台按能力逐步消费,避免系统过载。
3异步:非核心流程异步处理,如支付成功后,异步通知积分、优惠券服务,提升主流程响应速度。
4最终一致性:解决跨库 / 分布式事务问题,通过消息投递确保各系统数据最终同步。
2. 常用消息队列及区别?
消息队列 | 单机吞吐 | 开发语言 | 核心特点 | 适用场景 |
RabbitMQ | 万级 | Erlang | 支持复杂路由、死信队列等,但二次开发门槛高 | 业务逻辑复杂(如订单状态流转)、需要灵活路由的场景 |
RocketMQ | 十万级 | Java | 支持事务消息、定时消息,稳定性强,易二次开发 | 高并发业务、金融级场景(如支付对账) |
Kafka | 百万级 | Scala | 高吞吐、低延迟,最初为日志收集设计 | 海量数据传输(如日志同步、用户行为上报) |
3. Topic 和 Tag 分别是什么?有什么区别?
●Topic:消息的一级分类,代表一个业务大类(如 “订单消息”“支付消息”),是生产者发送和消费者订阅的基本单位。
●Tag:消息的二级分类,用于在 Topic 内部细分消息(如 “订单消息” 下的 “订单创建”“订单取消”),实现更精准的消息过滤。
●核心区别:Topic 是 “大类”,一个 Topic 对应多个业务场景;Tag 是 “小类”,在 Topic 内进一步区分消息类型,减少无效消费。
4. 消费者组是什么?
消费逻辑相同的消费者组成的集合,同一消费者组内的消费者共同消费一个 Topic 的消息,遵循 “集群消费” 规则(一条消息仅被组内一个消费者消费)。
5. 发送消息的模式有哪些?
1.同步消息:生产者发送消息后,需等待 Broker 返回 “发送成功” 确认,才继续执行后续逻辑,适用于需确保消息必达的场景(如支付结果通知)。
2.异步消息:生产者发送消息后无需等待确认,直接执行后续代码,Broker 会通过回调通知发送结果,适用于非核心、追求高吞吐的场景(如日志上报)。
3.单向消息:生产者仅发送消息,不关心 Broker 是否接收成功,无任何返回,适用于允许少量消息丢失的场景(如监控数据采集)。
6. 消息消费模式有哪些?
1.集群模式:一条消息仅被消费者组内的一个消费者消费,多消费者共同分担消费压力,是默认且最常用的模式(如订单消息由多个消费节点处理)。
2.广播模式:一条消息会被消费者组内的所有消费者消费,每个消费者都能获取全量消息,适用于通知类场景(如系统配置更新通知)。
7. 消息重试是什么?
当消费者消费消息返回 “失败”(如业务异常)时,Broker 触发的消息重新投递机制,流程如下:
1.首次消费失败后,Broker 将消息暂存,不立即重新投递;
2.按 “延迟级别” 投递:RocketMQ 默认有 18 个延迟级别(如 1s、5s、10s...),每失败一次,延迟级别 + 1,延长投递时间;
3.超过最大延迟级别后,消息进入 “死信队列”,需人工干预处理。
8. Broker 是什么?
RocketMQ 的核心服务节点,是部署在服务器上的 MQ 进程,主要负责消息的存储、转发、投递,以及与生产者 / 消费者的通信,是消息流转的核心载体。
9. NameServer 是什么?有什么作用?
NameServer 是 RocketMQ 的 “注册中心”,作用如下:
1Broker 注册:Broker 启动后向 NameServer 注册自身地址和 Topic 路由信息;
2路由发现:生产者发送消息、消费者订阅消息时,先向 NameServer 查询目标 Topic 对应的 Broker 地址,再与 Broker 通信。 (NameServer 无状态,可集群部署,确保高可用)
10. 消费者消费消息时,是从 Master 还是 Slave 拉取?
默认首次从 Master 节点拉取消息;Master 会在返回消息时,告知消费者 “下次可从 Master 或 Slave 拉取”(根据 Slave 同步状态动态判断),后续可从 Slave 拉取,减轻 Master 压力。
11. CommitLog 是什么?
RocketMQ 的核心存储文件,所有 Topic 的消息都会按 “顺序追加” 的方式写入 CommitLog(而非按 Topic 拆分),同时完成持久化,确保消息不丢失。
12. ConsumeQueue 是什么?存了哪些内容?
ConsumeQueue 是消息消费的核心索引文件,为每个 Topic 的每个 Queue 单独创建,用于快速定位 CommitLog 中的消息,存储内容包括:
●8 字节:消息在 CommitLog 中的偏移量(offset);
●4 字节:消息大小(方便一次读取完整消息);
●8 字节:消息 Tag 的 Hash 值(用于消费时过滤 Tag)。
13. 同步刷盘是什么意思?
生产者将消息发送给 Broker 后,Broker 会立即将消息写入 CommitLog 文件,并强制刷到磁盘,只有刷盘成功后,才向生产者返回 “发送成功” 的 ACK。 (优点:消息安全性高,不丢失;缺点:性能略低,适合金融等核心场景)
14. 延迟消息怎么实现?
RocketMQ 4.x 与 5.x 实现逻辑不同,具体如下:
●4.x 版本(仅仅支持18个时间级别):
a生产者发送延迟消息时,Broker 会将消息的 Topic 改为 “延迟 Topic”(如 SCHEDULE_TOPIC_XXXX),并按延迟级别存入对应队列;
bBroker 启动定时任务,扫描各延迟级别的队列,当消息到达延迟时间后,将 Topic 改回原 Topic,消费者即可正常订阅。
●5.x 版本:
a延迟消息存入专门的 time log 文件,按 “时间槽” 分类存储;
b通过 “时间轮” 调度机制,直接定位到期的消息,无需全量扫描,开销更低;
c支持任意延迟时间(不再局限于 18 个固定级别)。
15. 顺序消息怎么实现?
通过 “消息分区策略”,将同一业务链路的消息路由到同一个队列
1单列写入:通过 按消息 Key(如订单 ID)选择队列,相同 Key 的消息会写入同一个 Queue(确保生产顺序);
2单线程消费:同一个 Queue 只能由一个消费者线程消费,Broker 确保队列内消息按顺序投递,消费者按顺序处理(确保消费顺序)。
16. 事务消息怎么实现?
基于 “两阶段提交” 逻辑,确保本地事务与消息投递一致性,流程如下:
1生产者发送 “半消息”(Half Message)到 Broker,Broker 存储但标记为 “不可消费”,并返回成功;
2生产者执行本地事务(如数据库操作);
3若本地事务成功,生产者向 Broker 发送 commit 指令,Broker 标记消息为 “可消费”;若失败,发送 rollback 指令,Broker 删除半消息;
4若 Broker 长时间未收到 commit/rollback,会主动发起 “事务回查”(默认 60 秒一次,最多 15 次),生产者查询本地事务状态后,再返回最终指令;
5超过 15 次回查仍无结果,Broker 丢弃消息。
17. 消息积压怎么解决?
先判断积压原因(生产过快 / 消费过慢),再针对性处理:
1消费者扩容:若 Topic 的 Message Queue 数量 > 消费者数量,增加消费者实例,让更多消费者分担消费(每个消费者可分配多个 Queue);
2Queue 扩容 + 消息迁移:若 Queue 数量 ≤ 消费者数量,扩容消费者无效,需:
○新建临时 Topic,设置更多 Message Queue;
○用 “轻量消费者”(仅转发消息,不处理业务)将积压消息迁移到临时 Topic;
○扩容消费者消费临时 Topic,快速清理积压,完成后恢复原 Topic 消费。
18. 怎么解决消息不丢失?
需从 “生产、存储、消费” 三个环节全面保障:
●生产环节:用同步消息(确保 Broker 确认接收),开启重试机制(避免网络波动导致发送失败);
●存储环节:开启同步刷盘(消息强制刷盘),Broker 部署主从架构(Master 故障时 Slave 切换,避免单点丢失);
●消费环节:消费者处理完业务逻辑后,再提交消费进度(ack),避免未处理完就确认,导致消息丢失。
19. 重平衡是什么?
当消费者组内消费者数量变化(如新增 / 下线消费者)、或 Topic 的 Message Queue 数量变化时,RocketMQ 自动触发的 “队列重新分配” 机制。 目的是确保所有 Message Queue 都能被消费者组内的实例覆盖,避免队列闲置或重复消费,平衡消费压力。
20.怎么处理消息重复问题?
1、业务幂等:将消息的 “业务唯一 Key”(如订单 ID + 操作类型)作为数据库表的 唯一索引 / 主键,重复消息插入时会触发唯一键冲突。保证消息幂等,也就是多次调用和一次调用消结果是一样的。这样一来,消息消费多少次都是一样的。两次消费如果都不影响业务,我们可以不用做这些处理。。。时效性不高可以通过redis的setnx,生产者带一个uuid过来,如果设置进去了,就说明还没有被消费。
2、 消息去重:第二种是业务端,对重复的消息就不再消费了。这种方法 ,需要保证每条消息都有一个惟一的编号,通常是业务相关的,比如订单号,消费的记录需要落库,而且需要保证和消息确认这一步的原子性。
具体做法是可以建立一个消费记录表,拿到这个消息做数据库的insert操作。给这个消息做一个唯一主键(primary key)或者唯一约束,那么就算出现重复消费的情况,就会导致主键冲突,那么就不再处理这条消息。