消息中间件面试题库
生成时间:2026-05-23 15:55
本轮 消息中间件面试题(带答案)
【面试题】1. RabbitMQ的四种Exchange类型有什么区别?分别适用什么场景?
【标准答案】
RabbitMQ有四种Exchange,核心区别在于路由规则:
1. Direct Exchange(直连):精确匹配routing key,一对一。适合点对点消息,比如订单系统只给订单队列发消息。
2. Fanout Exchange(扇出):无视routing key,广播到所有绑定队列。适合广播场景,比如用户注册后同时发短信、邮件、积分。
3. Topic Exchange(主题):支持通配符匹配,*匹配一个单词,#匹配多个。适合多条件路由,比如日志系统按级别和模块路由,log.error.#匹配所有error日志。
4. Headers Exchange(头部):匹配消息头属性,性能差,基本不用。
实际选型:90%场景用Direct和Topic,Fanout用于广播,Headers几乎不用。
【面试题】2. Kafka的ISR机制是什么?为什么能保证数据不丢?
【标准答案】
ISR是In-Sync Replicas,同步副本集合,是Kafka高可用的核心。
机制原理:
- 每个Partition有一个Leader和多个Follower
- ISR里的副本跟Leader保持同步(默认落后不超过一定阈值)
- 只有ISR里的副本才有资格当选新Leader
acks=all时,Leader等ISR所有副本确认后才返回成功
为什么能保证不丢:
acks=all+min.insync.replicas=2,至少2个副本写入成功- 即使Leader挂了,ISR里还有副本有完整数据
- 配合
unclean.leader.election.enable=false,非ISR副本不能当选Leader
关键配置:acks=all、min.insync.replicas≥2、replication.factor≥3,这三个配置保底数据安全。
【面试题】3. RocketMQ的事务消息是怎么实现的?半消息是什么?
【标准答案】
RocketMQ事务消息解决分布式事务问题,核心是"半消息"机制。
半消息:暂不能被消费的消息,暂存在Broker,等本地事务执行成功后才对消费者可见。
完整流程:
- Producer发送半消息到Broker(消息状态为"暂不可消费") 2.Broker返回半消息发送成功
- Producer执行本地事务
- 根据本地事务结果,向Broker发送Commit或Rollback
- 如果Commit,消息变为可消费;Rollback则丢弃
关键机制-消息回查:
- 如果Producer挂了或网络超时,Broker没收到Commit/Rollback
- Broker会定期回查Producer本地事务状态
- Producer返回状态后,Broker做对应处理
适用场景:订单创建+库存扣减、支付成功+积分增加等分布式事务场景。
【面试题】4. 消息消费端如何保证幂等性?有几种方案?
【标准答案】
消息重复消费是必然的(网络抖动、重试等),消费端必须幂等。
方案一:唯一ID + 数据库去重
- 每条消息带唯一业务ID(如订单号)
- 消费前查数据库,已存在则跳过
- 数据库表加唯一索引,插入失败说明已处理
方案二:唯一ID + Redis去重
- 消费前用
SETNX设置key,设置成功则处理 - 设置过期时间,避免无限堆积
- 性能比数据库好,适合高并发
方案三:乐观锁/状态机
- 消息带版本号或期望状态
- 更新时加条件:
UPDATE order SET status=PAID WHERE id=xxx AND status=UNPAID - 影响行数为0说明已处理
方案四:Token机制
- 业务操作前先申请Token,消费时验证并销毁
- 适合需要强控制的场景
实际选型:Redis去重性能最好,数据库唯一索引最稳妥,乐观锁最常用。
【面试题】5. 线上出现消息积压,怎么快速处理?
【标准答案】
消息积压是线上常见问题,要快速止损。
第一步:定位原因
- 消费者处理慢?代码有性能问题或下游依赖慢
- 消费者数量不够?单机消费能力有限
- 消息量突增?活动或促销导致流量暴涨
第二步:紧急处理
- 临时扩容消费者:增加消费者实例,提高并发度
- 批量消费模式:一次拉取多条消息,减少网络开销
- 降级非核心逻辑:跳过非必要处理,先快速消费
- 新增临时队列:原有消费者继续处理,新消费者处理积压
第三步:根本解决
- 优化消费者代码性能
- 下游依赖做异步化或批量处理
- 合理规划分区数和消费者数量
关键指标:监控Lag(积压量),设置告警阈值,提前发现。
【面试题】6. Kafka为什么快?零拷贝和顺序写是什么?
【标准答案】
Kafka的高性能是架构设计的综合结果,核心有三个原因。
1. 顺序写磁盘
- 传统磁盘随机写慢,但顺序写可达数百MB/s
- Kafka的Partition内消息追加写入,全是顺序写
- 顺序写比随机写快几个数量级
2. 零拷贝(Zero-Copy)
- 传统数据传输:磁盘→内核→用户→内核→网卡,4次拷贝
- Kafka用
sendfile系统调用:磁盘→内核→网卡,只有2次拷贝 - 数据不经过用户空间,减少CPU开销
3. 批量与压缩
- 批量发送,减少网络IO次数
- 支持GZIP/Snappy/LZ4压缩,减少数据量
- 生产者批量聚合,消费者批量拉取
总结:顺序写解决磁盘瓶颈,零拷贝解决网络瓶颈,批量压缩解决CPU瓶颈。
【面试题】7. 如何保证消息的顺序性?有几种方案?
【标准答案】
消息顺序性分全局有序和分区有序,实现难度不同。
全局有序:
- 所有消息发到同一个Partition/Queue
- 只有一个消费者消费
- 性能差,实际很少用
分区有序:
- 同一个业务ID的消息发到同一个分区
- 每个分区只有一个消费者线程
- 常用方案,性能和顺序性平衡
具体实现(Kafka):
- 生产者指定Partition Key(如订单ID)
- 同一订单的消息路由到同一Partition
- 消费端单线程消费或按Key分发到单线程队列
具体实现(RocketMQ):
- 发送时指定MessageQueueSelector,按业务ID取模选队列
- 消费端用
MessageListenerOrderly,单线程顺序消费
注意点:
- 顺序消息不能用多线程消费,会乱序
- 消费失败要谨慎重试,避免阻塞后续消息
【面试题】8. RabbitMQ的死信队列DLX是什么?怎么用?
【标准答案】
死信队列(DLX)是RabbitMQ的消息回收站,处理无法正常消费的消息。
什么情况产生死信:
- 消息被NACK或Reject,且
requeue=false - 消息TTL过期
- 队列满了,新消息被丢弃
如何配置死信队列:
- 声明业务队列时,设置
x-dead-letter-exchange指向死信交换机 - 设置
x-dead-letter-routing-key指定路由键 - 死信交换机绑定死信队列
实际应用:
- 失败消息兜底:消费失败的消息进DLX,人工处理或重试
- 延迟队列:消息设TTL,过期后进DLX,实现延迟消费
- 消息审计:DLX里的消息记录日志,排查问题
最佳实践:DLX单独用一个Exchange,死信队列配告警,及时处理异常。
【面试题】9. 从生产到消费,全链路如何防止消息丢失?
【标准答案】
消息丢失可能发生在三个环节,每个环节都要防护。
生产端防丢:
- RabbitMQ:开启Confirm模式,
waitForConfirms()确认 - Kafka:
acks=all,所有ISR副本确认 - RocketMQ:同步发送,等待Broker返回
- 捕获发送异常,重试或落库补偿
Broker端防丢:
- 开启持久化:消息写入磁盘
- 配置副本:多副本保证数据安全
- 刷盘策略:同步刷盘或合理异步刷盘间隔
消费端防丢:
- 手动确认:业务成功后再ACK
- 捕获异常:失败不ACK,让消息重新入队
- 死信兜底:多次重试失败进DLX
关键原则:宁可重复不可丢。配置auto.commit=false,手动提交offset。
【面试题】10. Kafka消费者Group重平衡是什么?有什么问题?
【标准答案】
重平衡(Rebalance)是Consumer Group内消费者与分区重新分配的过程。
触发条件:
- 消费者加入或退出
- 订阅Topic的分区数变化
- 消费者心跳超时(默认10s)
- 消费者处理时间过长(max.poll.interval超时)
重平衡过程:
- 所有消费者停止消费,加入Group
- 选出Group Leader
- Leader分配分区方案
- 所有消费者按方案同步分配结果
重平衡的问题:
- 消费暂停:重平衡期间所有消费者停止消费
- 重复消费:offset提交不及时,可能导致消息重复
- 频繁重平衡:消费者频繁上下线导致消费抖动
优化方案:
- 合理设置
session.timeout.ms和heartbeat.interval.ms - 单次拉取消息数
max.poll.records不要太大 - 使用静态成员(
group.instance.id)减少不必要重平衡 - 消费逻辑要快,避免超过
max.poll.interval.ms
说明:本轮题目覆盖RabbitMQ、Kafka、RocketMQ核心原理,以及幂等性、顺序性、积压处理、全链路可靠性等通用问题,适合面试高频考点。