Skip to content

消息中间件面试题库 ​

生成时间:2026-05-24 20:10


本轮 消息中间件面试题(带答案) ​

【面试题】1. Kafka的Controller是什么?Controller选举过程是怎样的? ​

【标准答案】

Controller是Kafka集群的"大脑",负责分区状态管理、副本选举、主题管理等核心协调工作。

Controller职责:

  • 分区Leader选举(ISR中选新Leader)
  • 副本状态管理(ISR变更、副本上下线)
  • 主题创建/删除/分区扩容
  • Preferred Leader选举触发
  • 集群元数据同步给所有Broker

选举过程:

  1. 每个Broker启动时尝试在Zookeeper/KRaft创建/controller临时节点
  2. 第一个成功创建的Broker成为Controller
  3. 其他Broker监听该节点,发现Controller变更时触发重新选举
  4. 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)避免消息被慢消费者独占

实际优化方法:

java
// 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消费失败后自动重试,是保证消息可靠性的核心机制之一。

重试机制流程:

  1. Consumer返回RECONSUME_LATER,消费失败
  2. Broker将消息重新投递,延迟等级默认从3开始(10秒)
  3. 每次重试,延迟等级递增,最多重试16次
  4. 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%消费者组名

代码配置:

java
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+推荐

生产环境选择建议:

  1. 默认推荐ZSTD:

    • Kafka 2.1+原生支持
    • 压缩率接近GZIP,速度接近Snappy
    • 综合性能最优
    properties
    compression.type=zstd
  2. 高吞吐低延迟场景选LZ4:

    • 压缩解压速度最快
    • CPU开销最低
    • 适合消息量极大、实时性要求高的场景
  3. 存储成本敏感场景选GZIP:

    • 压缩率最高,节省磁盘
    • 但CPU开销大,生产端和解压端都要考虑
  4. 老版本兼容选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.ms10秒心跳超时判断Coordinator认为Consumer宕机,触发Rebalance
max.poll.interval.ms5分钟两次poll最大间隔Consumer主动离开组,触发Rebalance

核心区别:

  • session.timeout:心跳线程超时,被动判定死亡
  • max.poll.interval:消费逻辑处理太慢,主动触发离开

典型问题场景:

  1. 消费逻辑阻塞:

    • 比如poll后处理一批消息用了6分钟
    • 心跳正常发送,但超过max.poll.interval
    • 触发Rebalance,Consumer被踢出组
  2. Full GC或网络问题:

    • Consumer停止发送心跳超过session.timeout
    • Coordinator判定死亡,触发Rebalance

生产环境调优:

properties
# 心跳间隔,建议为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过滤流程:

  1. Producer发送消息,带Tag
  2. Broker存储消息,CommitLog存完整消息体,ConsumeQueue存Tag哈希
  3. Consumer拉取时,Broker先比较ConsumeQueue中的Tag哈希
  4. Tag匹配才返回消息体,不匹配直接跳过

SQL92过滤原理:

  • 支持更复杂的过滤条件,如a > 10 AND b = 'hello'
  • 消息发送时设置用户属性:
java
message.putUserProperty("orderAmount", "1000");
message.putUserProperty("region", "beijing");
  • 消费者订阅时写SQL表达式:
java
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:

  1. 日志清理高效:

    • Kafka按Segment维度删除过期数据
    • 整个Segment直接删除,不需要逐条清理
    • 避免随机写带来的性能问题
  2. 快速定位消息:

    • 通过offset二分查找定位Segment
    • 再通过索引文件定位具体位置
    • 稀疏索引减少内存占用
  3. 文件管理方便:

    • 单个文件不会无限增长
    • 方便备份、迁移、删除

Segment滚动策略:

properties
# 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
  • 触发后:同上,阻塞生产者
  • 临界保护:防止磁盘写满导致崩溃

配置调整:

bash
# 内存告警阈值调整为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

避免触发的最佳实践:

  1. 内存优化:

    • 控制队列长度,避免消息堆积
    • 合理设置prefetch,避免消费者积压太多未ACK消息
    • 非持久化消息控制数量
  2. 磁盘管理:

    • 设置合理的消息TTL,过期自动删除
    • 定期清理死信队列
    • 监控磁盘使用率,提前扩容
  3. 监控告警:

    • 设置内存使用率告警(如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宕机可能丢失未同步的数据

配置方式:

xml
<!-- 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控制每个消费者处理速度
  • 慢消费者可能独占消息(不公平)

对比总结:

维度KafkaRocketMQRabbitMQ
负载均衡粒度分区MessageQueue消息级别
消费者数量限制≤分区数无硬性限制无限制
分配策略多种可选8种策略轮询
重平衡开销大(Stop-the-world)小无

面试加分点:

  • Kafka的CooperativeSticky策略减少Rebalance开销,逐步迁移而非全量重新分配
  • RocketMQ消费者数量理论上无限制,但太多会增加Client端计算压力
  • RabbitMQ的prefetch不均衡可能导致消息分配不均,需监控

说明:本轮题目覆盖Controller选举、Prefetch优化、消息重试、压缩算法、心跳机制、Tag过滤、日志段、资源告警、主从复制、负载均衡等核心考点,适合面试高频考察。