消息队列面试题
本页只放 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 |
basicAck、basicNack、basicReject 区别 | 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 和商业场景回到 消息堆积与背压 等知识点页学习。
