Skip to content

消息队列面试题

本页只放 MQ 面试标准回答、追问点和知识点跳转。消息堆积、背压、幂等、ACK、重试、死信、Kafka Lag、RabbitMQ Ready/Unacked 的详细原理统一回到知识点页学习。

项目训练入口:MQ 商业场景训练营

使用方式

mermaid
flowchart TD
    A["面试页:组织标准回答"] --> B["知识点页:理解原理和排查流程"]
    B --> C["项目场景:订单、搜索同步、短信、日志、采集任务"]

MQ 通用高频问题

面试题标准回答原理知识点
MQ 怎么从零学到生产级不能只背异步、削峰、解耦,要按生产者发送、Broker 存储、消费者消费、ACK/Offset、可靠性、重复消费、幂等、顺序、事务消息、重试、死信、堆积、背压和选型这条主线学习。学完后要能用验收清单证明自己会画链路、会写 Demo、会排查堆积、会解释选型边界。MQ 从零到生产级掌握MQ 从零到精通验收清单
MQ 有什么作用MQ 主要用于异步解耦、削峰填谷和最终一致性。生产者把消息写到 Broker,下游消费者按自身能力处理,避免主链路被慢服务拖垮。MQ 从零到生产级掌握消息队列总览
MQ 会不会丢消息可能会。要分别看生产者发送确认、Broker 持久化和主从复制、消费者业务成功后 ACK。生产中通常通过可靠发送、持久化、手动 ACK、重试和补偿降低丢失风险。MQ 从零到生产级掌握
MQ 为什么会重复消费多数 MQ 更容易保证至少投递一次。消费者处理成功但 ACK 或 offset 提交失败、网络超时、Broker 重试、消费者重平衡都可能导致重复投递,所以消费端必须幂等。消息堆积与背压:幂等
消息顺序怎么保证通常只能保证局部顺序,比如同一个订单 ID 路由到同一个分区或队列,由同一个消费者顺序处理。全局顺序会牺牲吞吐,商业项目很少要求全局有序。RocketMQ顺序消息Kafka分区顺序
MQ 怎么选型RabbitMQ 适合复杂路由和传统任务队列;Kafka 适合高吞吐事件流、日志、埋点、CDC 和回放;RocketMQ 适合业务消息、事务消息、顺序消息、重试和堆积能力要求较高的场景。MQ 从零到生产级掌握消息队列总览

消息堆积与背压

面试题标准回答原理知识点
MQ 消息堆积怎么办先判断是计划内削峰还是异常堆积。排查时看 Topic、Queue、ConsumerGroup、生产 TPS、拉取 TPS、成功 TPS、Lag 或 Queue Depth、失败率、重试、死信、消费者线程池和下游耗时。处理上先止血,例如限流、暂停补数据、隔离失败消息;再定位瓶颈,例如消费者并发、分区队列数、线程池、数据库慢 SQL、远程接口;最后消化存量,例如扩容消费者、批量处理、优化下游、延迟重试和死信处理。不能一上来清队列或 reset offset。堆积排查证据链
一条消息消费过程里哪些地方会导致堆积消息从 Broker 到消费者后,要经历拉取或投递、反序列化、提交本地线程池、执行业务、访问 DB/ES/Redis/HTTP、业务成功落库、ACK 或提交 Offset。任何一步变慢都会降低成功 TPS。排查时要把指标映射到链路阶段,而不是只看消费者数量。消费全过程:堆积到底卡在哪里
生产 TPS、拉取 TPS、成功 TPS 有什么区别生产 TPS 是上游写入速度,拉取 TPS 是消费者从 Broker 拿到消息的速度,成功 TPS 是业务成功并 ACK 或提交 Offset 的速度。堆积是否真正被消化看成功 TPS,不看拉取 TPS。拉得快但业务慢,只是把堆积从 Broker 搬到消费者内存和线程池。生产 TPS、拉取 TPS、成功 TPS 的区别
消费者扩容一定能解决堆积吗不一定。扩容只有在瓶颈是消费者并发不足,并且分区或队列允许并行时才有效。Kafka 一个分区同一时刻只能被同组一个消费者消费;RabbitMQ 要看队列、prefetch 和 ACK;RocketMQ 要看队列数、顺序消息和消费线程。如果瓶颈在数据库、远程接口、重试风暴、热点分区或 Broker,盲目扩容可能把下游打挂。本质:最短板决定吞吐
扩容消费者后短暂有效,后面又开始堆积,什么原因这说明扩容只解决了表层并发,没有解决真正瓶颈。刚扩容时消费 TPS 会上升,所以 Lag 短暂下降;但更多消费者可能把压力打到 DB、ES、Redis、远程接口、连接池、线程池或 Broker 上,导致单条消息耗时升高,最终消费 TPS 又下降。也可能是分区/队列并行度不足、热点 key、重试风暴、顺序消息阻塞、Rebalance 抖动或上游生产继续上涨。排查时看扩容前后的生产 TPS、拉取 TPS、成功 TPS、P95/P99、Lag 分布、错误率、重试量、线程池、连接池和下游慢日志。扩容反弹的指标时间线
扩容后怎么快速判断根因先确认消费者是否真正上线,再看拉取 TPS 是否上升;如果拉取 TPS 不升,查分区/队列并行度、Broker 和消费者配置;如果拉取 TPS 上升但成功 TPS 不升,查线程池、DB、ES、HTTP、错误率和重试;如果只有少数分区 Lag 高,查热点 key、慢消息或局部消费者异常。根因决策树
Lag 分布是什么Lag 分布是看每个分区、队列或 MessageQueue 分别落后多少,而不是只看总 Lag。总 Lag 只能说明积压规模,分布才能判断是所有通道都慢,还是少数通道因为热点 key、慢消息、消费者异常、顺序阻塞或重试风暴卡住。Kafka 看 Partition Lag,RocketMQ 看 MessageQueue Diff,RabbitMQ 类比看不同 Queue 的 Ready、Unacked 和消费者分布。Lag 分布与堆积定位
堆积后怎么估算多久能恢复先拿到当前堆积量、生产 TPS 和成功消费 TPS。净消化速度等于成功消费 TPS 减生产 TPS,预计追平时间等于当前堆积量除以净消化速度。如果净消化速度小于等于 0,说明还在继续落后,必须先限流止血或提升真实消费能力。评估时还要看最老消息等待时间和 Broker 磁盘保留窗口。容量评估模板
堆积时最老消息等待时间为什么重要总 Lag 只说明数量,最老消息等待时间说明业务已经延迟多久。100 万条日志可能可接受,但 100 条支付回调等待 10 分钟就可能严重超 SLA。生产告警应该同时看 Lag、消费 TPS、失败率和最老消息等待时间。容量评估模板
什么是背压背压是下游处理不过来时,对上游或拉取端施加压力控制,避免消息无限进入本机内存或把下游压垮。常见做法包括生产者限流、消费者暂停拉取、RabbitMQ prefetch、Kafka pause/resume、有界线程池、信号量、熔断降级、延迟重试和死信队列。背压怎么设计
背压为什么不能只靠无界线程池排队无界线程池队列只是把 Broker 里的堆积搬到消费者 JVM 里,短期看 Lag 可能下降,实际业务成功 TPS 没提升,还会造成内存上涨、GC 频繁、任务超时和 OOM。正确做法是有界线程池、高低水位、暂停拉取、控制下游并发和失败隔离。背压不是简单少拉一点
Kafka 并发消费时 Offset 为什么不能随便提交最大值Offset 表示某个分区已经安全处理到的位置。并发处理时,offset 103 成功但 102 失败,不能提交到 104,否则 102 会被跳过造成消息丢失。应该按分区记录连续成功位点,只提交已经连续成功处理到的位置。Offset 提交为什么比想象中难
什么是毒消息,怎么处理毒消息是每次消费都失败的消息,例如格式错误、业务状态不满足、代码 Bug 或长期不可用依赖。它会反复重试占满消费者,拖慢正常消息。要区分可重试和不可重试异常,使用延迟重试、最大重试次数、死信队列、告警、修复后重放和人工补偿。毒消息为什么会拖垮整个消费组
RabbitMQ Ready 和 Unacked 高分别说明什么Ready 高说明消息还在队列里等待投递,可能是消费者不足、消费者掉线或 prefetch 太小。Unacked 高说明消息已经投递给消费者但还没 ACK,通常是消费者处理慢、业务卡住、ACK 异常或 prefetch 太大。Ready 高优先看消费者在线和投递速率,Unacked 高优先看业务耗时和 ACK 时机。RabbitMQ 堆积指标
Kafka Lag 很高怎么处理先看是所有分区 Lag 高还是个别分区高。所有分区高通常是整体消费能力不足或下游慢,可以扩容、批量消费、优化下游。个别分区高通常是 key 热点、单条慢消息或该分区消费者异常。还要确认消费者数量是否小于分区数,超过分区数继续加实例没有意义。不能随便 reset offset 到 latest,否则会跳过未处理消息。Lag 分布与堆积定位

可靠性与失败处理

面试题标准回答原理知识点
为什么不能提前 ACK提前 ACK 后 Broker 会认为消息已经处理成功。如果后续业务失败,消息已经被删除或 offset 已提交,只能依赖人工补偿或主库重建。正确做法是业务真正成功后再 ACK 或提交 offset。RabbitMQ 手动 ACK
失败消息怎么处理要区分短暂故障和永久故障。短暂故障可以延迟重试;永久故障应该进入死信队列或异常表,避免无限快速重试形成重试风暴。处理失败消息前,消费端必须幂等。消息堆积与背压
为什么不能直接清空队列清空队列可能丢业务数据,导致订单、库存、搜索索引、通知状态不一致。除非业务确认消息可以丢,或者可以从主库、日志、binlog、补偿任务中完整重建,否则不能直接清。不能做什么
堆积时怎么判断消息能不能跳过先看消息是否是唯一事实来源。支付、库存、订单核心状态通常不能跳过;ES 同步、缓存刷新、部分通知可以在确认主库、binlog、业务流水或原始文件可重建后跳过,再通过补偿任务恢复。技术上能 reset offset 不代表业务上允许丢。堆积处理决策表
幂等消费怎么做常见做法是用业务唯一号、消息 ID、消费日志表、数据库唯一索引、状态机或 Redis 去重。核心是重复收到同一消息时,不重复产生业务副作用。幂等是消化堆积的前提

RabbitMQ 高频问题

面试题标准回答原理知识点
RabbitMQ ACK 是什么ACK 是消费者告诉 Broker“这条消息已经处理完成”的确认信号。Broker 不知道业务是否真的成功,只能根据 ACK 决定是否删除消息。核心业务要使用手动 ACK,业务成功并完成幂等落库后再 basicAck;失败时根据异常类型进入延迟重试或死信队列。ACK、重试和死信
自动 ACK 和手动 ACK 有什么区别自动 ACK 是消息投递给消费者后立即认为成功,消费者宕机或业务失败会丢消息;手动 ACK 是业务成功后再确认,可靠性更高。订单、支付、库存、ES 同步这类重要业务都应该用手动 ACK。自动 ACK 和手动 ACK
basicAckbasicNackbasicReject 区别basicAck 表示消费成功;basicNack 表示拒绝消息,支持批量并可选择是否重新入队;basicReject 只能拒绝单条,也可选择是否重新入队。requeue=false 且配置了死信交换机时,消息会进入死信链路。手动 ACK 的三个动作
为什么不建议失败后一直 requeue=true因为失败消息会立即回到原队列并被再次消费,如果错误不可恢复,会形成重试风暴,正常消息被挤占,消费者和下游都被打满。生产上要区分可重试和不可重试异常,可重试进入延迟重试,不可重试进入死信。为什么不建议无限 requeue
RabbitMQ 死信队列有什么用死信队列用于隔离无法正常消费的异常消息,避免毒消息反复重试拖垮主消费链路。死信不是垃圾桶,必须告警、记录原始消息和失败原因,修复后按幂等规则重放或人工补偿。死信队列应该怎么用
RabbitMQ 如何做延迟重试常见做法是业务消费失败后把消息投递到重试队列,重试队列设置 TTL,TTL 到期后通过死信交换机路由回原业务队列。超过最大重试次数后进入真正的死信队列。这样可以避免失败消息立即循环消费。重试策略
RabbitMQ Ready 高和 Unacked 高分别说明什么Ready 高说明消息还在队列中等待投递,常见原因是消费者不足、掉线、prefetch 太小或投递异常;Unacked 高说明消息已经投递给消费者但还没 ACK,常见原因是业务处理慢、线程池卡住、下游慢、ACK 分支没执行或 prefetch 太大。生产排查:Ready 和 Unacked 怎么看
RabbitMQ prefetch 有什么作用prefetch 控制单个消费者最多持有多少条未 ACK 消息。太大容易让大量消息堆在消费者本地形成高 Unacked,太小会限制吞吐。它是 RabbitMQ 消费端背压的重要参数,要结合单条耗时、消费者并发和下游容量压测。prefetch 为什么重要

项目话术

text
在订单同步 ES、短信通知、采集任务异步入库这类场景里,我会把 MQ 堆积监控作为核心指标。除了 Lag 或 Queue Depth,还会看最老消息等待时间、消费 TPS、失败率、重试队列、死信、消费者线程池和下游 DB/ES/接口耗时。处理堆积时不会直接清消息,而是先限流止血,再定位瓶颈,最后通过扩容、批处理、失败隔离和补偿任务消化存量。

常见追问

追问回答方向跳转
为什么加消费者没用看分区/队列并行度、下游瓶颈、热点 key、重试风暴、Rebalance 抖动和顺序阻塞。典型根因全过程
Lag 分布怎么看先看总 Lag,再看各分区/队列是否均匀;均匀说明整体慢,倾斜说明热点或局部阻塞。Lag 分布与堆积定位
怎么算多久能消化完当前堆积量 / (当前消费 TPS - 当前生产 TPS),如果消费 TPS 小于生产 TPS,永远追不上。堆积核心公式
堆积时能不能跳过消息取决于业务是否允许丢弃,以及是否能从主库补偿。订单、库存、支付类不能随便跳过。不能做什么
顺序消息堆积怎么办找到卡住的消息和队列,修复数据、人工处理或补偿,不能盲目跳过破坏顺序。RocketMQ顺序消息

本章小结

MQ 面试回答要先给结论,再给排查路径,最后说明边界。标准回答放在本页,详细原理、流程图、排查命令、Demo 和商业场景回到 消息堆积与背压 等知识点页学习。