RocketMQ 面试核心知识点总结

一、消息不丢失机制

1. 消息丢失的核心环节

消息链路中 4 个关键丢失风险点,跨网络传输和缓存异步刷盘是主要场景:

2. 生产者端防丢失方案

(1)发送确认机制
发送方式 特点 代码示例
单向发送 效率高,可能丢消息 producer.sendOneway(msg);
同步发送 安全可靠,效率低 SendResult result = producer.send(msg, 20000);
异步发送 安全与效率平衡 producer.send(msg, new SendCallback() {<br>@Override<br>public void onSuccess(SendResult res) {}<br>@Override<br>public void onException(Throwable e) {}<br>});
(2)事务消息机制(RocketMQ 特有)

核心流程:

适用场景:电商订单创建与支付确认等分布式事务场景

3. Broker 端防丢失方案

(1)刷盘机制
  • 同步刷盘(SYNC_FLUSH):写入日志即调用 fsync,消息不丢失但 IO 压力大
  • 异步刷盘(ASYNC_FLUSH):定期刷盘,性能好但断电可能丢缓存消息
  • 核心配置:flushDiskType=SYNC_FLUSH(生产环境推荐)
(2)主从同步机制
集群类型 同步方式 数据安全性 切换逻辑
普通集群 同步 Master(SYNC_MASTER)/ 异步 Master(ASYNC_MASTER) 高(SYNC_MASTER) Master 挂了不自动切换
DLedger 集群 Raft 协议多数派确认 极高 自动选举 Leader,数据一致性优先

关键差异:Kafka Leader 崩溃后新 Leader 以自身数据为准,可能丢失未同步消息;RocketMQ Master 重启后继续同步未同步数据,不丢失

4. 消费者端防丢失方案

  • 核心原则:先处理消息,再提交消费确认

  • 风险场景:异步处理消息时提前返回成功状态

    // 错误示例(可能丢失消息)
    consumer.registerMessageListener((msgs, context) -> {
    new Thread(() -> {
    // 异步处理业务,可能未执行完就返回成功
    }).start();
    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    });

    // 正确示例(同步处理)
    consumer.registerMessageListener((msgs, context) -> {
    // 同步处理业务逻辑
    processBusiness(msgs);
    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    });

  • 重试机制:未收到确认时 Broker 会重复投递,RocketMQ 通过 Offset,RabbitMQ 通过重新入队

5. 极端场景(MQ 集群全挂)处理

  • 降级方案:生产者发送失败时写入本地缓存(如 Redis、文件)
  • 恢复机制:独立线程循环重试发送缓存消息,MQ 恢复后自动补送

6. 零丢失方案总结(trade-off)

环节 方案 代价
生产者 同步发送 + 重试 降低吞吐
Broker 同步刷盘 + DLedger 集群 IO / 网络负担增加
消费者 同步处理 + 确认 无法异步提升效率
集群故障 降级缓存 增加存储成本

二、消息顺序性保障

1. 核心概念

  • 局部有序:同一业务维度(如同一订单)的消息有序(实际业务常用)
  • 全局有序:整个 Topic 的消息有序(极少场景需要,性能极差)

2. 实现机制(RocketMQ)

两大关键

  1. 生产者:通过分区算法将同业务标识消息写入同一 MessageQueue
  2. 消费者:单个 Consumer 线程对应单个 MessageQueue,串行消费

3. 不同 MQ 对比

MQ 产品 顺序性保障方式 特点
RocketMQ 分区绑定 + 单线程消费 支持局部有序,配置灵活
Kafka 单 Partition 单线程消费 天生支持局部有序
RabbitMQ 单 Queue 对应单 Consumer 经典队列需手动保证绑定关系

三、消息幂等性处理

1. 幂等性定义

  • 多次处理同一消息,业务结果一致(不重复创建订单、不重复扣款)

2. 生产者端幂等

(1)RocketMQ 实现
  • 自动生成唯一messageIdMessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX
  • Broker 通过该 ID 判断重复消息
(2)Kafka 实现
  • 开启幂等性配置(默认开启),核心机制:
    • PID:生产者唯一标识
    • Sequence Number:每个 PID+Partition 的单调递增序号
    • Broker 仅接收序号 = 当前 SN+1 的消息

3. 消费者端幂等

(1)去重依据(优先级)
  1. 业务唯一标识(推荐):如订单 ID、支付流水号(通过msg.setKey(业务ID)设置)
  2. MQ 内置唯一 ID:messageId(批量 / 事务消息场景可能失效)
(2)实现方式
复制代码
// 伪代码示例
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs) {
    for (MessageExt msg : msgs) {
        String businessId = msg.getKey(); // 订单ID
        // 1.查缓存/数据库判断是否已处理
        if (isProcessed(businessId)) {
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
        // 2.处理业务逻辑
        processBusiness(msg);
        // 3.标记为已处理(缓存/数据库)
        markAsProcessed(businessId);
    }
    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
(3)异常处理
  • 重试队列:重复投递的消息进入重试队列(%RETRY%消费者组名
  • 死信队列:多次重试失败进入死信队列(%DLQ%消费者组名),需手动调整权限后处理

四、消息积压处理

1. 积压风险

  • RocketMQ/Kafka:日志文件过期会删除未消费消息
  • RabbitMQ:经典队列积压严重影响服务端性能

2. 处理方案

(1)临时扩容(快速见效)
  • 核心限制:Consumer 实例数 ≤ MessageQueue 数(RocketMQ/Kafka)
  • 操作步骤:
    1. 增加 Consumer 实例(不超过 Queue 数)
    2. 优化 Consumer 消费逻辑(关闭非核心业务、异步处理非关键步骤)
(2)分流处理(大量积压时)
  • 操作步骤:
    1. 创建新 Topic,配置更多 MessageQueue
    2. 部署临时消费者,仅负责将旧 Topic 消息转存到新 Topic
    3. 新 Topic 部署足够多 Consumer 实例快速消费
    4. 消费完成后恢复正常架构

五、常见面试题及参考答案

1. RocketMQ 如何保证消息不丢失?

  • 生产者:使用同步发送 + 重试机制,关键场景用事务消息
  • Broker:配置同步刷盘 + DLedger 高可用集群
  • 消费者:同步处理消息后提交确认,避免异步提前返回成功
  • 极端情况:降级缓存 + 后台重试发送

2. 如何保证消息的顺序性?

  • 实现局部有序:生产者将同业务标识消息写入同一 MessageQueue,消费者单线程消费单个 MessageQueue
  • 不推荐全局有序:Topic 只配置 1 个 Queue,性能极差,无实际业务价值

3. 如何解决消息重复消费问题?

  • 生产者端:RocketMQ 通过唯一 messageId 去重,Kafka 通过 PID+SequenceNumber 保证幂等
  • 消费者端:基于业务唯一标识(如订单 ID)做幂等处理,通过缓存 / 数据库记录处理状态

4. 消息积压了怎么处理?

  • 短期:增加 Consumer 实例(不超过 Queue 数),优化消费逻辑
  • 长期:创建多 Queue 新 Topic,临时分流积压消息,批量快速消费

5. RocketMQ 的事务消息原理是什么?

  • 两阶段提交:先发送半消息,执行本地事务后再确认 Commit/Rollback
  • 兜底机制:Broker 定期回查本地事务状态,避免事务结果丢失

6. RocketMQ 与 Kafka 在消息安全上的核心差异?

  • 主从同步:RocketMQ Master 挂了不切换,重启后同步未同步数据;Kafka 会选举新 Leader,丢失未同步消息
  • 设计初衷:RocketMQ 源于金融场景,优先数据安全;Kafka 源于日志收集,优先服务可用性
相关推荐
小迷糊的学习记录18 小时前
0.1 + 0.2 不等于 0.3
前端·javascript·面试
程序员敲代码吗18 小时前
面试中sessionStorage问题引发深度探讨
面试·职场和发展
源代码•宸20 小时前
大厂技术岗面试之谈薪资
经验分享·后端·面试·职场和发展·golang·大厂·职级水平的薪资
马猴烧酒.21 小时前
【面试八股|JVM虚拟机】JVM虚拟机常考面试题详解
jvm·面试·职场和发展
Serene_Dream1 天前
JVM 并发 GC - 三色标记
jvm·面试
愚者游世1 天前
Delegating Constructor(委托构造函数)各版本异同
开发语言·c++·程序人生·面试·改行学it
信码由缰1 天前
Spring Boot 面试问题
spring boot·后端·面试
马猴烧酒.2 天前
【面试八股|Java集合】Java集合常考面试题详解
java·开发语言·python·面试·八股
闻哥2 天前
从测试坏味道到优雅实践:打造高质量单元测试
java·面试·单元测试·log4j·springboot
南风知我意9572 天前
【前端面试5】手写Function原型方法
前端·面试·职场和发展