RocketMQ 常见面试题汇总

一、RocketMQ 基础

1. RocketMQ 是什么?

复制代码
# 核心特点:
- 阿里开源,Apache顶级项目
- 分布式消息中间件
- 高可用、高吞吐、低延迟
- 支持发布订阅、顺序消息、事务消息
- 支持消息轨迹、消息过滤

2. RocketMQ 架构

复制代码
# 核心组件:
1. NameServer: 无状态注册中心
   - 服务发现与路由管理
   - 轻量级,集群部署
   
2. Broker: 消息存储和转发
   - 主从架构,支持同步/异步复制
   - 消息存储、查询、消费队列管理
   
3. Producer: 消息生产者
   - 与NameServer建立长连接
   - 从NameServer获取路由信息
   
4. Consumer: 消息消费者
   - Push/Pull两种模式
   - 集群/广播两种消费模式

3. RocketMQ 与其他MQ对比

特性 RocketMQ Kafka RabbitMQ ActiveMQ
设计目标 金融级 日志处理 企业级 传统消息
吞吐量 极高 极高 高 中等
延迟 毫秒级 毫秒级 微秒级 毫秒级
可用性 非常高 高 高 中等
事务消息 支持 不支持 支持 支持
消息顺序 支持 支持 不支持 支持
消息追溯 支持 支持 有限 有限
成熟度 高 极高 极高 高

二、NameServer

1. NameServer 作用

复制代码
# 核心功能:
1. 服务注册:Broker启动时注册
2. 服务发现:Producer/Consumer获取路由
3. 心跳检测:监控Broker存活状态
4. 路由管理:维护Topic-Broker映射

# 特点:
- 无状态设计,可水平扩展
- 数据存储在内存
- 通过心跳维持数据
- 部署奇数台(2n+1)

2. NameServer 工作流程

复制代码
// 1. Broker注册
Broker → NameServer: 注册Topic、Broker、Queue信息
// 2. Producer/Consumer查询
Producer → NameServer: 查询Topic路由
// 3. 心跳机制
Broker → NameServer: 每30秒发送心跳
// 4. 故障检测
NameServer: 120秒无心跳,剔除Broker

三、Broker

1. Broker 架构

复制代码
# 核心模块:
1. Remoting: 网络通信层
2. Client Manager: 客户端管理
3. Store Service: 存储服务
4. HA Service: 高可用服务
5. Index Service: 索引服务

# 存储结构:
Broker
├── CommitLog    # 所有消息顺序存储
├── ConsumeQueue # 逻辑消费队列
├── IndexFile    # 消息索引
└── Config       # 配置信息

2. 消息存储机制

复制代码
# 存储流程:
1. 消息写入CommitLog(顺序写)
2. 异步构建ConsumeQueue
3. 异步构建IndexFile

# 文件结构:
CommitLog: 1GB固定大小,顺序写入
ConsumeQueue: 30万条记录,固定大小
IndexFile: 哈希索引,支持快速查找

3. 主从复制

复制代码
# 复制方式:
1. 同步复制:主从都写成功返回ACK
2. 异步复制:主成功即返回

# 配置:
brokerRole:
  - ASYNC_MASTER   # 异步复制主节点
  - SYNC_MASTER    # 同步复制主节点
  - SLAVE          # 从节点

四、Producer

1. 生产者类型

复制代码
// 1. 普通生产者
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroup");
producer.send(message);

// 2. 事务消息生产者
TransactionMQProducer producer = new TransactionMQProducer("TranProducerGroup");
producer.setTransactionListener(new TransactionListenerImpl());

// 3. 延迟消息生产者
message.setDelayTimeLevel(3);  // 延迟级别

2. 发送模式

复制代码
// 1. 同步发送
SendResult result = producer.send(message);

// 2. 异步发送
producer.send(message, new SendCallback() {
    public void onSuccess(SendResult result) {}
    public void onException(Throwable e) {}
});

// 3. 单向发送
producer.sendOneway(message);

3. 消息类型

复制代码
// 1. 普通消息
Message msg = new Message("Topic", "Tag", "Key", body);

// 2. 顺序消息
MessageQueueSelector selector = new MessageQueueSelector() {
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
        Integer id = (Integer) arg;
        int index = id % mqs.size();
        return mqs.get(index);
    }
};
producer.send(msg, selector, orderId);

// 3. 事务消息
TransactionSendResult result = producer.sendMessageInTransaction(msg, null);

// 4. 定时/延迟消息
msg.setDelayTimeLevel(3);  // 延迟10秒

五、Consumer

1. 消费者类型

复制代码
// 1. 推模式(推荐)
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroup");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
        ConsumeConcurrentlyContext context) {
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});

// 2. 拉模式
DefaultLitePullConsumer consumer = new DefaultLitePullConsumer("PullConsumerGroup");

2. 消费模式

复制代码
// 1. 集群消费(默认)
consumer.setMessageModel(MessageModel.CLUSTERING);

// 2. 广播消费
consumer.setMessageModel(MessageModel.BROADCASTING);

3. 消费进度管理

复制代码
# 进度存储:
- 集群模式:Broker存储
- 广播模式:本地存储

# 重置消费位点:
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
// CONSUME_FROM_LAST_OFFSET   最后位置
// CONSUME_FROM_FIRST_OFFSET  开始位置
// CONSUME_FROM_TIMESTAMP     指定时间

六、消息存储与清理

1. 存储流程

复制代码
# 写入流程:
1. Producer发送消息到Broker
2. Broker写入CommitLog(顺序写)
3. 异步构建ConsumeQueue
4. 异步构建IndexFile

# 读取流程:
1. Consumer发送拉取请求
2. Broker查询ConsumeQueue获取CommitLog偏移量
3. 从CommitLog读取消息
4. 返回给Consumer

2. 文件清理策略

复制代码
# 清理条件:
1. 文件过期:默认72小时
2. 磁盘空间不足
3. 手动触发清理

# 配置:
fileReservedTime=72        # 文件保留时间(小时)
deleteWhen=04             # 清理时间(凌晨4点)
diskMaxUsedSpaceRatio=75  # 最大磁盘使用率

七、顺序消息

1. 顺序消息原理

复制代码
# 全局顺序:
- Topic只有一个队列
- 严格保证全局顺序
- 性能较低

# 分区顺序:
- 同一业务ID的消息发到同一队列
- 同一队列内保证顺序
- 使用MessageQueueSelector

2. 顺序消费实现

复制代码
// 生产者
producer.send(msg, new MessageQueueSelector() {
    @Override
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
        Long orderId = (Long) arg;
        long index = orderId % mqs.size();
        return mqs.get((int) index);
    }
}, orderId);

// 消费者(顺序监听器)
consumer.registerMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs,
        ConsumeOrderlyContext context) {
        // 顺序处理
        return ConsumeOrderlyStatus.SUCCESS;
    }
});

八、事务消息

1. 事务消息流程

复制代码
# 两阶段提交:
1. 发送half消息
2. 执行本地事务
3. 提交/回滚消息

# 状态检查:
- Broker定时检查half消息状态
- 回调生产者检查事务状态

2. 事务消息实现

复制代码
// 事务监听器
public class TransactionListenerImpl implements TransactionListener {
    
    // 执行本地事务
    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        try {
            // 执行本地业务
            boolean success = doBusiness();
            return success ? LocalTransactionState.COMMIT_MESSAGE 
                          : LocalTransactionState.ROLLBACK_MESSAGE;
        } catch (Exception e) {
            return LocalTransactionState.UNKNOW;
        }
    }
    
    // 检查本地事务状态
    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        // 检查业务状态
        return checkBusinessStatus() ? LocalTransactionState.COMMIT_MESSAGE
                                    : LocalTransactionState.ROLLBACK_MESSAGE;
    }
}

九、延迟消息

1. 延迟级别

复制代码
# 18个固定级别:
1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

# 实现原理:
1. 发送延迟消息
2. Broker将消息存入SCHEDULE_TOPIC_XX队列
3. 定时任务扫描到期消息
4. 投递到目标Topic

2. 自定义延迟

复制代码
// 不支持自定义延迟时间
// 可通过以下方式模拟:
1. 使用定时任务+普通消息
2. 使用Redis ZSet实现
3. 使用时间轮算法

十、消息过滤

1. 过滤方式

复制代码
# 1. Tag过滤(推荐)
- 一个消息一个Tag
- 消费者订阅Tag表达式
- 如: TagA || TagB

# 2. SQL过滤
- 基于消息属性过滤
- 支持SQL92语法
- 如: a > 5 AND b = 'abc'

# 3. 类过滤
- 实现MessageFilter接口
- 完全自定义过滤逻辑

2. Tag过滤示例

复制代码
// 生产者
Message msg = new Message("Topic", "TagA", "Key", body);

// 消费者
consumer.subscribe("Topic", "TagA || TagB");

// 不推荐:* 表示订阅所有Tag
consumer.subscribe("Topic", "*");

十一、高可用与负载均衡

1. Producer负载均衡

复制代码
// 默认策略:轮询
List<MessageQueue> mqs = producer.fetchPublishMessageQueues("Topic");
MessageQueue mq = mqs.get(index % mqs.size());

// 自定义策略
producer.send(msg, new MessageQueueSelector() {
    @Override
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
        // 自定义选择逻辑
        return mqs.get(hash(arg) % mqs.size());
    }
}, shardingKey);

2. Consumer负载均衡

复制代码
# 集群模式负载均衡:
1. 获取Topic所有队列
2. 获取消费者组所有消费者
3. 平均分配队列
4. 每20秒重新平衡

# 分配策略:
- 平均分配(默认)
- 环形分配
- 机房就近分配
- 一致性哈希分配

3. Broker高可用

复制代码
# 主从架构:
- 一主多从
- 同步/异步复制
- 自动故障转移

# 部署建议:
- 至少2主2从
- 跨机房部署
- 监控报警

十二、消息轨迹

1. 轨迹数据

复制代码
# 记录信息:
1. 生产者轨迹
   - 发送时间
   - 发送状态
   - 发送IP
   
2. 消费者轨迹
   - 消费时间
   - 消费状态
   - 消费IP
   - 重试次数

2. 轨迹配置

复制代码
# 开启轨迹
traceTopicEnable=true
traceTopicName=RMQ_SYS_TRACE_TOPIC

# 轨迹存储
- 默认存储到Broker
- 可自定义存储
- 支持可视化查询

十三、性能优化

1. 生产者优化

复制代码
// 1. 批量发送
List<Message> messages = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    messages.add(new Message("Topic", "Tag", "Key", body));
}
SendResult result = producer.send(messages);

// 2. 压缩消息
message.setCompressed(true);

// 3. 合理设置Topic队列数
// 建议:队列数 = 生产者数 * 消费者数

2. 消费者优化

复制代码
// 1. 批量消费
consumer.setConsumeMessageBatchMaxSize(32);

// 2. 并发消费
consumer.setConsumeThreadMin(20);
consumer.setConsumeThreadMax(64);

// 3. 拉取批量
consumer.setPullBatchSize(32);

3. Broker优化

复制代码
# 1. 存储优化
flushDiskType=ASYNC_FLUSH  # 异步刷盘
flushCommitLogLeastPages=4  # 最少页数

# 2. 内存优化
mappedFileSizeCommitLog=1073741824  # 1GB
mappedFileSizeConsumeQueue=300000  # 30万条

# 3. 网络优化
sendMessageThreadPoolNums=16
pullMessageThreadPoolNums=16

十四、监控与运维

1. 监控指标

复制代码
# 关键指标:
1. 消息堆积
   - 监控Topic消费延迟
   
2. 生产/消费TPS
   - 监控消息吞吐量
   
3. 系统资源
   - CPU、内存、磁盘、网络
   
4. 错误率
   - 发送失败率
   - 消费失败率

2. 运维命令

复制代码
# 1. 集群状态
mqadmin clusterList -n localhost:9876

# 2. Topic状态
mqadmin topicStatus -n localhost:9876 -t TopicTest

# 3. 消费进度
mqadmin consumerProgress -n localhost:9876 -g ConsumerGroup

# 4. 消息查询
mqadmin queryMsgById -n localhost:9876 -i 0A9A003F00002A9F00000000000003B4

# 5. 发送消息
mqadmin sendMsgStatus -n localhost:9876 -t TopicTest -p "hello" -k "key"

十五、常见问题与解决方案

1. 消息丢失

复制代码
# 可能原因:
1. 异步刷盘丢失
2. 主从复制丢失
3. 消费者处理异常

# 解决方案:
1. 同步刷盘 + 同步复制
2. 事务消息
3. 消费端幂等处理
4. 消息轨迹追踪

2. 消息重复

复制代码
# 可能原因:
1. 生产者重试
2. 消费者重试
3. Broker重投

# 解决方案:
1. 消费端幂等处理
2. 使用全局唯一ID
3. 记录已处理消息

3. 消息堆积

复制代码
# 处理方案:
1. 增加消费者实例
2. 提高消费能力
3. 临时Topic分流
4. 跳过堆积消息
5. 设置死信队列

十六、高级特性

1. 消息重试

复制代码
// 顺序消息不重试
// 普通消息重试机制:
// 重试次数:16次
// 重试间隔:越来越长
// 重试Topic:%RETRY%ConsumerGroup

// 消费失败处理
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
    ConsumeConcurrentlyContext context) {
    try {
        // 处理消息
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    } catch (Exception e) {
        // 返回RECONSUME_LATER会重试
        return ConsumeConcurrentlyStatus.RECONSUME_LATER;
    }
}

2. 死信队列

复制代码
# 死信Topic:
%DLQ%ConsumerGroup

# 进入条件:
1. 最大重试次数后仍失败
2. 默认重试16次

# 处理:
1. 监控死信队列
2. 人工干预处理
3. 重新投递

十七、RocketMQ 5.0 新特性

1. 轻量级队列

复制代码
# 特点:
- 更轻量的消费进度管理
- 支持更高并发
- 简化运维

2. 多副本机制

复制代码
# DLEDGER模式:
- 基于Raft协议
- 自动选主
- 强一致性

3. 云原生支持

复制代码
# 特性:
- 容器化部署
- 弹性伸缩
- 服务网格集成

十八、常见面试题

1. 基础问题

复制代码
Q1: RocketMQ如何保证消息不丢失?
A:
1. 生产者:同步发送+重试
2. Broker:同步刷盘+同步复制
3. 消费者:正确消费后确认

Q2: NameServer在集群中作用?
A:
1. 服务注册与发现
2. 路由信息管理
3. 心跳检测
4. 无状态设计,可水平扩展

Q3: CommitLog和ConsumeQueue区别?
A:
- CommitLog:物理存储,所有消息顺序写入
- ConsumeQueue:逻辑队列,存储消息在CommitLog的偏移

2. 进阶问题

复制代码
Q4: 如何实现顺序消息?
A:
1. 生产者:相同业务ID发送到同一队列
2. 消费者:顺序消费同一队列
3. 使用MessageQueueSelector和MessageListenerOrderly

Q5: 事务消息实现原理?
A:
1. 发送half消息
2. 执行本地事务
3. 提交/回滚消息
4. Broker定时检查未完成事务

Q6: 如何解决消息堆积?
A:
1. 增加消费者实例
2. 提高批量消费大小
3. 优化消费逻辑
4. 临时扩容Topic队列
5. 设置死信队列

3. 实战问题

复制代码
Q7: 如何设计消息幂等性?
A:
1. 消息唯一ID
2. 业务状态检查
3. 数据库唯一约束
4. Redis防重表
5. 分布式锁

Q8: 如何选择同步/异步复制?
A:
- 同步复制:金融场景,强一致性
- 异步复制:日志场景,高性能
- 根据业务容忍度选择

Q9: 如何监控RocketMQ集群?
A:
1. 自带监控命令
2. 集成Prometheus
3. 使用RocketMQ-Exporter
4. 配置告警规则
5. 监控关键指标

面试准备建议:

  1. 深入理解架构设计原理

  2. 掌握消息存储和流转机制

  3. 熟悉各种消息类型的使用场景

  4. 了解高可用和负载均衡策略

  5. 准备实际项目中的问题解决经验

  6. 关注新版本特性变化

  7. 动手搭建和配置集群

高频考点:

  • RocketMQ核心组件与架构

  • 消息存储机制(CommitLog/ConsumeQueue)

  • 顺序消息实现原理

  • 事务消息两阶段提交

  • 消息高可用方案

  • 消息过滤与路由

  • 性能优化策略

  • 常见问题排查与解决

相关推荐
IT机器猫1 天前
RocketMQ基础一
rocketmq
蚂蚁背大象2 天前
RocketMQ-Rust 1.0.0 发布:用 Rust 做消息队列,这次有哪些变化?
rust·开源·rocketmq
此时不提桶,更待何时2 天前
06-08-B-RocketMQ面试与生产事故实战
面试·rocketmq
醉颜凉2 天前
Kafka 与 RabbitMQ/RocketMQ 选型对比:场景匹配、性能基准与迁移成本
kafka·消息队列·rabbitmq·rocketmq·中间件选型
此时不提桶,更待何时3 天前
06-04-A-RocketMQ存储深水区与源码解析详解
rocketmq
此时不提桶,更待何时3 天前
06-02-A-RocketMQ消息特性与消费机制详解
rocketmq
青山木12 天前
RocketMQ 入门到原理(六):可靠性全景
java·后端·中间件·架构·rocketmq
青山木12 天前
RocketMQ 入门到原理(五):特殊消息类型
java·后端·中间件·架构·rocketmq
青山木13 天前
RocketMQ 入门到原理(三):消息存储原理
java·后端·中间件·架构·rocketmq
科学熊13 天前
RocketMQ 一主两从集群搭建与 SpringBoot 集成完整方案
rocketmq