🚀 RocketMQ
架构 · 事务消息 · 延迟消息 · 顺序消息 · 高可用
1. RocketMQ 的核心架构?
- NameServer:注册中心(轻量,无状态,可多台)——Broker 启动注册路由,Producer/Consumer 拉取路由
- Broker:消息存储节点(主从结构),一个 Topic 多个队列(MessageQueue)
- Producer / Consumer:生产/消费;Consumer 有 push 模式(底层是长轮询 pull)
- 消息存储:CommitLog(所有消息顺序写一个文件)+ ConsumeQueue(每个队列的索引,定长条目)——顺序写 CommitLog 保证高性能,索引消费
- 高可用:Broker 主从 + 自动故障转移(DLedger/Raft 模式);多副本存储
🎯 面试要点
- 对比 Kafka:RocketMQ 的"队列"概念(一个 Topic 多队列)类似分区;NameServer 类似轻量 ZK
- CommitLog + ConsumeQueue 双写设计是"顺序写高吞吐 + 随机读也快"的关键
- RocketMQ 是阿里开源、Java 实现、功能丰富(事务/延迟/顺序都内置)
2. RocketMQ 事务消息原理?(解决本地事务与发消息原子性)
要解决的问题:先写库再发消息(库成功消息失败 → 下游没收到);先发消息再写库(消息成功库失败 → 下游收到不存在的业务)。
两阶段 + 回查:
- 半消息(half message):生产者先发送"半消息"(消费者不可见,暂存)
- 执行本地事务:半消息发送成功后,执行本地事务(写库)
- 提交或回滚:本地事务成功 → commit 半消息(消费者可见);失败 → rollback(消息丢弃)
- 事务回查:若第 3 步因宕机丢失,Broker 会回调查询本地事务状态(checkLocalTransaction)决定 commit/rollback——保证最终一致
事务消息 API 要点
TransactionMQProducer producer = new TransactionMQProducer("group");
producer.setTransactionListener(new TransactionListener() {
@Override public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
return doBizAndReturnState(); // ① 本地事务,返回 COMMIT/ROLLBACK/UNKNOW
}
@Override public LocalTransactionState checkLocalTransaction(MessageExt msg) {
return queryBizStatusAndReturn(); // ② 回查(Broker 调用)
}
});
🎯 面试要点
- 对比本地消息表:事务消息把"记录 + 发送"搬进了 MQ 内部(半消息 = 待确认消息)
- 回查机制保证"不确定状态"最终确定——最终一致性
3. 延迟消息怎么实现?
- RocketMQ 支持 18 个固定延迟级别:1s/5s/10s/30s/1m/2m/3m/4m/5m/6m/7m/8m/9m/10m/20m/30m/1h/2h——消息设置 delayLevel,Broker 按级别放入对应的延迟队列,到点再转入真实队列
- 实现原理:4.x 是 18 个固定延迟级别,每级一个延迟队列 + 定时任务扫描;5.x 改为 Broker 端 TimerWheel + timerlog,支持毫秒级任意延迟(18 级仅为兼容旧 API 保留)
- 场景:订单超时未支付自动关闭(30 分钟)、限时活动提醒
- 对比:Kafka 原生无延迟消息(需要时间轮自实现或 Redis 延迟队列);RabbitMQ 用死信队列/插件模拟
延迟消息用法
Message msg = new Message("order-timeout", body);
msg.setDelayTimeLevel(15); // 15 = 10 分钟(索引从 1 开始)
producer.send(msg);
🎯 面试要点
- 面试延伸:订单超时关闭的多种方案(定时任务轮询 / 延迟队列 / Redis 过期监听——延迟队列最优雅)
- 任意精度延迟需自研时间轮(Kafka 的 TimerWheel)
4. RocketMQ 的顺序消息/广播/死信?
- 顺序消息:MessageQueueSelector 按业务键选同一队列 + 消费端串行(MessageListenerOrderly)
- 广播消费:CONSUME_MODE_BROADCASTING——组内每个消费者都收全量(集群模式才竞争)
- 死信队列(DLQ):消费重试 16 次仍失败 → 进 %DLQ% 队列,人工/脚本处理——可靠性兜底
- 消息过滤:Tag(轻量过滤)+ SQL92 属性过滤
🎯 面试要点
- 死信队列是 MQ 可靠性的最后一环,面试讲"失败兜底"必提
- Tag 过滤:一个 Topic 多业务用 Tag 区分,比拆 Topic 轻量