消息中间件面试题库
生成时间:2026-05-24 20:10
本轮 消息中间件面试题(带答案)
【面试题】1. Kafka的Controller是什么?Controller选举过程是怎样的?
【标准答案】
Controller是Kafka集群的"大脑",负责分区状态管理、副本选举、主题管理等核心协调工作。
Controller职责:
- 分区Leader选举(ISR中选新Leader)
- 副本状态管理(ISR变更、副本上下线)
- 主题创建/删除/分区扩容
- Preferred Leader选举触发
- 集群元数据同步给所有Broker
选举过程:
- 每个Broker启动时尝试在Zookeeper/KRaft创建
/controller临时节点 - 第一个成功创建的Broker成为Controller
- 其他Broker监听该节点,发现Controller变更时触发重新选举
- Controller变更时,新Controller从ZK/KRaft加载全量元数据
Controller故障恢复:
- Controller所在Broker宕机,临时节点自动删除
- 其他Broker收到通知,重新竞争创建临时节点
- 新Controller重新初始化集群状态,触发必要的Leader选举
面试加分点:
- Kafka 2.8+引入KRaft模式,不再依赖Zookeeper,Controller选举由KRaft Raft协议完成
- KRaft模式下Controller是Raft Quorum的一部分,天然高可用
- 生产环境建议监控Controller变更频率,频繁变更说明集群不稳定
【面试题】2. RabbitMQ的Prefetch Count是什么?如何设置才能最大化消费者吞吐?
【标准答案】
Prefetch Count控制消费者一次最多能"预取"多少条消息,是消费者限流和吞吐优化的关键参数。
工作原理:
- Consumer启动时声明prefetch count(如设置为10)
- RabbitMQ向该Consumer推送消息,未ACK的消息数不超过prefetch count
- Consumer ACK一条,RabbitMQ才能再推送一条
设置策略:
| 场景 | Prefetch值建议 | 原因 |
|---|---|---|
| 消费逻辑极快(纯内存操作) | 较大(50-100) | 减少网络往返,提升吞吐 |
| 消费逻辑较慢(有IO操作) | 中等(10-20) | 平衡吞吐和公平分配 |
| 消费逻辑很慢(复杂计算/外部调用) | 较小(1-5) | 避免消息被慢消费者独占 |
实际优化方法:
// Spring AMQP配置
spring.rabbitmq.listener.simple.prefetch=10
// 或原生Java客户端
channel.basicQos(10); // prefetch count = 10坑点与最佳实践:
- Prefetch太大:消息可能被一个慢消费者独占,其他消费者空闲
- Prefetch太小:网络往返次数多,吞吐下降
- 建议:从10开始,压测观察消费者CPU和消息积压情况,逐步调优
- 多消费者场景:确保总prefetch不超过队列消息堆积能力
面试加分点:全局QoS(basicQos(0, prefetch, true))可限制整个Connection的prefetch,而非单个Channel。
【面试题】3. RocketMQ的消息重试机制是怎样的?重试次数用完怎么办?
【标准答案】
RocketMQ消费失败后自动重试,是保证消息可靠性的核心机制之一。
重试机制流程:
- Consumer返回
RECONSUME_LATER,消费失败 - Broker将消息重新投递,延迟等级默认从3开始(10秒)
- 每次重试,延迟等级递增,最多重试16次
- 16次重试后仍失败,消息进入死信队列(DLQ)
延迟等级对应延迟时间:
等级1: 1s 等级2: 5s 等级3: 10s 等级4: 30s
等级5: 1m 等级6: 2m 等级7: 3m 等级8: 4m
等级9: 5m 等级10: 6m 等级11: 7m 等级12: 8m
等级13: 9m 等级14: 10m 等级15: 20m 等级16: 30m
等级17: 1h 等级18: 2h重试Topic规则:
- 原始Topic:
ORDER_TOPIC - 重试Topic:
%RETRY%消费者组名 - 死信Topic:
%DLQ%消费者组名
代码配置:
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
try {
// 业务处理
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
} catch (Exception e) {
// 返回RECONSUME_LATER触发重试
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
});
// 设置最大重试次数(默认16次)
consumer.setMaxReconsumeTimes(10);死信队列处理:
- 死信队列的消息需要人工介入或编写专门的DLQ消费者
- 监控DLQ的消息数量,设置告警
面试加分点:
- 重试消息会带上
RECONSUME_TIMES属性,消费时可判断重试次数 - 顺序消息的重试会阻塞整个队列,谨慎使用
- 可以自定义重试延迟等级,覆盖默认配置
【面试题】4. Kafka支持哪些压缩算法?生产环境如何选择?
【标准答案】
Kafka支持四种压缩算法:GZIP、Snappy、LZ4、ZSTD,各有优劣。
压缩算法对比:
| 算法 | 压缩率 | 压缩速度 | 解压速度 | CPU开销 | 适用场景 |
|---|---|---|---|---|---|
| GZIP | 高 | 慢 | 慢 | 高 | 网络带宽受限、存储成本敏感 |
| Snappy | 中 | 快 | 快 | 低 | CPU敏感、追求低延迟 |
| LZ4 | 中 | 极快 | 极快 | 极低 | 高吞吐、实时性要求高 |
| ZSTD | 高 | 中 | 中 | 中 | 综合最优,Kafka 2.1+推荐 |
生产环境选择建议:
默认推荐ZSTD:
- Kafka 2.1+原生支持
- 压缩率接近GZIP,速度接近Snappy
- 综合性能最优
propertiescompression.type=zstd高吞吐低延迟场景选LZ4:
- 压缩解压速度最快
- CPU开销最低
- 适合消息量极大、实时性要求高的场景
存储成本敏感场景选GZIP:
- 压缩率最高,节省磁盘
- 但CPU开销大,生产端和解压端都要考虑
老版本兼容选Snappy:
- Kafka早期版本默认压缩
- 兼容性好,生态成熟
压缩配置位置:
- Producer端压缩:
compression.type=zstd - Broker端可配置默认压缩(Producer未指定时生效)
- Consumer端自动解压,无需配置
面试加分点:
- 批量发送(
batch.size)+ 压缩效果更好,单条消息压缩意义不大 - 压缩比例:文本日志类可达5-10倍,JSON数据约3-5倍,已压缩的二进制数据效果差
- 监控Producer和Broker的CPU,压缩会增加CPU开销
【面试题】5. Kafka消费者心跳机制是怎样的?session.timeout和max.poll.interval有什么区别?
【标准答案】
Kafka消费者通过心跳机制与Group Coordinator保持连接,两个超时参数作用不同。
心跳机制:
- Consumer后台线程定期发送心跳到Group Coordinator
- 心跳间隔由
heartbeat.interval.ms控制(默认3秒) - Coordinator根据心跳判断Consumer存活状态
两个关键超时参数:
| 参数 | 默认值 | 作用 | 超时后果 |
|---|---|---|---|
session.timeout.ms | 10秒 | 心跳超时判断 | Coordinator认为Consumer宕机,触发Rebalance |
max.poll.interval.ms | 5分钟 | 两次poll最大间隔 | Consumer主动离开组,触发Rebalance |
核心区别:
session.timeout:心跳线程超时,被动判定死亡max.poll.interval:消费逻辑处理太慢,主动触发离开
典型问题场景:
消费逻辑阻塞:
- 比如poll后处理一批消息用了6分钟
- 心跳正常发送,但超过
max.poll.interval - 触发Rebalance,Consumer被踢出组
Full GC或网络问题:
- Consumer停止发送心跳超过
session.timeout - Coordinator判定死亡,触发Rebalance
- Consumer停止发送心跳超过
生产环境调优:
# 心跳间隔,建议为session.timeout的1/3
heartbeat.interval.ms=3000
# 心跳超时,建议10-30秒
session.timeout.ms=10000
# 消费处理最大间隔,根据业务最长处理时间设置
max.poll.interval.ms=300000 # 5分钟
# 单次poll消息数,控制处理时间
max.poll.records=500面试加分点:
- 两个参数失效都会触发Rebalance,但根因不同
- 消费逻辑慢要调大
max.poll.interval,网络不稳定要调大session.timeout - 频繁Rebalance是常见性能问题,排查思路:先看消费时间是否超限
【面试题】6. RocketMQ的Tag过滤是什么原理?SQL92过滤又是什么?
【标准答案】
RocketMQ支持两种消息过滤方式:Tag过滤和SQL92过滤。
Tag过滤原理:
- 消息发送时指定Tag:
message.setTags("OrderPaid") - 消费者订阅时指定Tag:
consumer.subscribe("Topic", "TagA || TagB") - Broker端在ConsumeQueue中存储Tag哈希码(8字节)
- 消费者拉取消息时,Broker先按Tag哈希过滤,减少网络传输
Tag过滤流程:
- Producer发送消息,带Tag
- Broker存储消息,CommitLog存完整消息体,ConsumeQueue存Tag哈希
- Consumer拉取时,Broker先比较ConsumeQueue中的Tag哈希
- Tag匹配才返回消息体,不匹配直接跳过
SQL92过滤原理:
- 支持更复杂的过滤条件,如
a > 10 AND b = 'hello' - 消息发送时设置用户属性:
message.putUserProperty("orderAmount", "1000");
message.putUserProperty("region", "beijing");- 消费者订阅时写SQL表达式:
consumer.subscribe("Topic",
MessageSelector.bySql("orderAmount > 500 AND region = 'beijing'"));两者对比:
| 维度 | Tag过滤 | SQL92过滤 |
|---|---|---|
| 性能 | 高(哈希比较) | 较低(需解析消息体) |
| 灵活性 | 单字段、简单匹配 | 多字段、复杂表达式 |
| 存储开销 | 无额外开销 | 需存储属性 |
| 使用场景 | 简单分类过滤 | 复杂条件筛选 |
面试加分点:
- Tag过滤在Broker端完成,大幅减少网络传输
- SQL92过滤需要Broker解析消息属性,有一定性能开销
- 生产环境建议:简单分类用Tag,复杂筛选用SQL92但要评估性能
【面试题】7. Kafka的日志段(Log Segment)是什么?为什么要分成多个Segment?
【标准答案】
Kafka的每个Partition物理上由多个Log Segment组成,每个Segment是一个滚动文件。
Segment结构:
.log文件:存储实际消息数据.index文件:稀疏索引,存储offset到物理位置的映射.timeindex文件:时间索引,按时间戳查找消息
Segment命名规则:
- 文件名为该Segment起始Offset(20位补零)
- 如
00000000000000000000.log、00000000000000123456.log
为什么要分Segment:
日志清理高效:
- Kafka按Segment维度删除过期数据
- 整个Segment直接删除,不需要逐条清理
- 避免随机写带来的性能问题
快速定位消息:
- 通过offset二分查找定位Segment
- 再通过索引文件定位具体位置
- 稀疏索引减少内存占用
文件管理方便:
- 单个文件不会无限增长
- 方便备份、迁移、删除
Segment滚动策略:
# Segment大小,默认1GB
log.segment.bytes=1073741824
# 时间滚动,默认7天
log.roll.hours=168
# 日志保留时间
log.retention.hours=168日志清理策略:
- 删除(Delete):超过保留时间或大小的Segment直接删除
- 压缩(Compact):保留每个Key的最新Value,旧Value被清理
面试加分点:
.index是稀疏索引,不是每条消息都有索引项- 稀疏索引权衡了内存占用和查找效率
- Segment越小,清理越频繁但文件越多
【面试题】8. RabbitMQ的内存告警和磁盘告警机制是什么?如何避免触发?
【标准答案】
RabbitMQ有两种资源告警机制,触发时会阻塞生产者,保护Broker稳定运行。
内存告警(Memory Alarm):
- 默认阈值:物理内存的40%(
vm_memory_high_watermark=0.4) - 触发后:阻塞所有生产者连接,停止接收消息
- 消费者仍可消费,等待内存下降后恢复
磁盘告警(Disk Alarm):
- 默认阈值:磁盘剩余空间 < 50MB
- 触发后:同上,阻塞生产者
- 临界保护:防止磁盘写满导致崩溃
配置调整:
# 内存告警阈值调整为0.6
rabbitmqctl set_vm_memory_high_watermark 0.6
# 磁盘告警阈值调整为1GB
rabbitmqctl set_disk_free_limit 1GB
# 或在配置文件中
vm_memory_high_watermark.relative = 0.6
disk_free_limit.absolute = 1GB避免触发的最佳实践:
内存优化:
- 控制队列长度,避免消息堆积
- 合理设置prefetch,避免消费者积压太多未ACK消息
- 非持久化消息控制数量
磁盘管理:
- 设置合理的消息TTL,过期自动删除
- 定期清理死信队列
- 监控磁盘使用率,提前扩容
监控告警:
- 设置内存使用率告警(如30%时告警)
- 设置磁盘剩余空间告警(如剩余20%告警)
- 触发告警前主动干预
面试加分点:
- 内存告警后会触发内存换页(page out),将部分数据写入磁盘
- 持久化消息不会增加内存压力(直接写磁盘)
- 生产环境建议预留足够内存和磁盘,避免触发告警影响业务
【面试题】9. RocketMQ主从复制是怎样的?同步复制和异步复制怎么选?
【标准答案】
RocketMQ主从复制保证Broker高可用,有同步和异步两种模式。
主从复制架构:
- Master Broker:处理读写请求
- Slave Broker:从Master同步数据,只提供读服务
- 同一Broker组内,Master和Slave数据相同
同步复制(SYNC_MASTER):
- Master收到消息后,同步复制到所有Slave
- 所有Slave确认后才向Producer返回成功
- 数据安全性高,Master宕机不丢数据
- 延迟较高,吞吐量受影响
异步复制(ASYNC_MASTER):
- Master收到消息后立即返回成功
- 异步将消息复制到Slave
- 延迟低,吞吐量高
- Master宕机可能丢失未同步的数据
配置方式:
<!-- broker配置文件 -->
brokerRole=SYNC_MASTER <!-- 同步复制 -->
brokerRole=ASYNC_MASTER <!-- 异步复制 -->
brokerRole=SLAVE <!-- 从节点 -->生产环境选型建议:
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 金融交易、订单核心链路 | 同步复制 | 数据安全优先 |
| 日志收集、行为轨迹 | 异步复制 | 吞吐量优先,可接受小概率丢失 |
| 混合场景 | 同步复制 + 异步刷盘 | 平衡性能和安全 |
注意事项:
- 同步复制至少需要2个节点(1主1从)
- Slave节点可以配置只读,分担Master读压力
- 新版RocketMQ支持DLedger模式,基于Raft实现自动主从切换
面试加分点:
- 主从复制 + 同步刷盘 = 最高可靠性,但性能最差
- 异步复制 + 异步刷盘 = 最高性能,但可能丢数据
- 实际生产多用同步复制 + 异步刷盘,平衡可靠性和性能
【面试题】10. 消息队列消费者组的负载均衡策略是怎样的?不同MQ有什么差异?
【标准答案】
消费者组的负载均衡决定消息如何分配给消费者,不同MQ实现差异较大。
Kafka消费者组Rebalance:
- Consumer Group由Group Coordinator管理
- 分区分配策略:Range(默认)、RoundRobin、Sticky、CooperativeSticky
- Range策略:按分区数/消费者数均匀分配,尽量连续
- 触发条件:消费者加入/退出、分区数变化、心跳超时
Range策略示例:
- Topic有7个分区,3个消费者
- 消费者1:分区0,1,2
- 消费者2:分区3,4
- 消费者3:分区5,6
RocketMQ负载均衡:
- 由Client端计算分配
- 支持8种策略:平均分配、环形分配、机房分配等
- 默认平均分配:按MessageQueue数量/消费者数分配
- 不像Kafka受分区数限制,可动态扩展消费者
RabbitMQ负载均衡:
- 没有消费者组概念
- 同一队列的多个消费者,消息轮询分发
- Prefetch Count控制每个消费者处理速度
- 慢消费者可能独占消息(不公平)
对比总结:
| 维度 | Kafka | RocketMQ | RabbitMQ |
|---|---|---|---|
| 负载均衡粒度 | 分区 | MessageQueue | 消息级别 |
| 消费者数量限制 | ≤分区数 | 无硬性限制 | 无限制 |
| 分配策略 | 多种可选 | 8种策略 | 轮询 |
| 重平衡开销 | 大(Stop-the-world) | 小 | 无 |
面试加分点:
- Kafka的CooperativeSticky策略减少Rebalance开销,逐步迁移而非全量重新分配
- RocketMQ消费者数量理论上无限制,但太多会增加Client端计算压力
- RabbitMQ的prefetch不均衡可能导致消息分配不均,需监控
说明:本轮题目覆盖Controller选举、Prefetch优化、消息重试、压缩算法、心跳机制、Tag过滤、日志段、资源告警、主从复制、负载均衡等核心考点,适合面试高频考察。