/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
RabbitMQ 高频面试题(完整详解,后端面试直接背诵)
一、基础概念篇
1. 什么是消息队列?使用 MQ 有哪些作用?
定义:消息队列是进程间 / 服务间异步通信的中间件,生产者发送消息存入队列,消费者异步拉取消息。 四大核心作用:
⚠️ 缺点: 系统复杂度上升;消息一致性、顺序、重复消费、消息丢失都需要额外处理;引入 MQ 带来运维成本。
2. RabbitMQ 核心组件?
- Producer 生产者:发送消息应用
- Consumer 消费者:接收消息应用
- Connection:TCP 物理连接
- Channel 信道:连接内轻量级逻辑通道,推荐一个连接多个 channel,不大量创建 Connection
- Exchange 交换机:接收消息,路由转发到队列,不存储消息
- Queue 队列:存储消息,等待消费者消费
- Binding 绑定:交换机和队列之间的绑定关系,携带 routingKey
- Virtual Host 虚拟主机:隔离权限、交换机、队列,多环境复用一套 MQ 服务
3. RabbitMQ 交换机有哪几种类型?路由规则?
4. Exchange 没有绑定队列,消息会怎样?
消息直接丢失。交换机只负责路由,自身不持久存储消息。
二、消息可靠性(面试重中之重)
消息丢失三大场景:生产者丢失、MQ 服务丢失、消费者丢失
5. 如何保证消息不丢失?完整方案
(1)生产者端防止消息丢失
- 普通 confirm:异步监听回调
- 批量 confirm:一次性等待多条确认 原理:消息发送到交换机后,MQ 异步返回 ack/nack;nack 代表发送失败,本地重试投递。
最佳实践:Confirm + Return 组合使用
(2)MQ 服务端防止消息丢失
队列和消息开启持久化:
⚠️ 持久化仅写入磁盘,宕机恢复后消息存在;磁盘刷盘依然有短暂丢失窗口(操作系统页缓存),极端断电仍可能丢消息。
(3)消费者端防止消息丢失:手动 ACK
默认自动 ACK:MQ 消息一推送给消费者,立刻删除消息。 如果消费者正在处理消息进程崩溃 → 消息丢失。
解决方案:关闭自动 ACK,手动 ACK
- channel.basicAck(deliveryTag, false):成功消费,通知 MQ 删除消息
- channel.basicNack(deliveryTag, false, true):消费失败,消息重新入队
6. 消息 Nack 什么时候重回队列?无限重试怎么办?
basicNack第三个参数 requeue=true,消息返回队列头部再次投递。 问题:异常消息一直重试,阻塞队列。 解决方案:
三、死信队列 DLX(高频)
7. 什么是死信?消息成为死信的条件
消息无法被正常消费,会转发到死信交换机:
DLX 使用流程
8. TTL 消息过期时间两种设置方式,区别?
⚠️ 重要坑: 消息过期不会立刻删除!RabbitMQ 只会在消息到达队首时才判断是否过期。 如果队首消息长期不过期,后面已经过期的消息会一直堆积,定时任务场景不要依赖 TTL 做延时任务!
9. RabbitMQ 如何实现延时队列?两种方案
四、消息重复消费、幂等性
10. 为什么会产生消息重复消费?
根本原因:网络波动导致 ack 丢失 流程:消费者处理完业务,发送 ack 给 RabbitMQ,网络中断,MQ 没有收到 ack;等待超时后重新推送消息 → 重复消费。 所有 MQ 都存在该问题,不是 RabbitMQ 特有。
11. 如何解决重复消费?核心:保证消费接口幂等
三种方案:
禁止方案:不要让 MQ 保证只投递一次!MQ 只能保证至少一次投递(At-Least-Once)
五、消息顺序问题
12. RabbitMQ 能否保证消息有序?原生有序条件
原生满足有序的前提:
一旦开启多个消费者、消息 nack 重回队列,顺序彻底打乱。
13. 需要严格消息顺序如何实现?
方案 1:单队列 + 单一消费者(并发低,适合低流量) 方案 2:消息分区,按业务 id 哈希路由到不同队列,每个队列单消费者(主流方案) 例:同一订单所有消息发送到同一个队列,保证订单内有序,不同订单并行。
不要幻想多消费者同时全局有序,做不到。
六、集群模式
14. RabbitMQ 三种集群模式区别
15. 集群脑裂怎么处理?
网络分区(脑裂)集群分裂成两部分,各自提供服务,消息不一致。 解决: 配置cluster_partition_handling策略,常用:
- pause_minority:少数派节点自动暂停,避免两边同时写入(生产常用)
七、生产常见坑 & 运维
16. 大量消息堆积如何排查与处理?
原因:消费者消费速度 < 生产速度;消费者阻塞、死循环、卡住。 风险: 内存暴涨、触发 MQ 限流、阻塞生产者,严重 MQ 宕机。
处理方案:
17. Channel 和 Connection 区别,开发规范?
- Connection:TCP 长连接,开销大;一个服务建议少量连接
- Channel:连接内虚拟通道,轻量,线程安全(Spring AMQP 中注意多线程使用规范) 规范:一个 Connection 创建多个 Channel,禁止每个线程新建 Connection
18. 什么是流量控制 Flow Control?
RabbitMQ 内存 / 磁盘达到阈值,触发流量控制,阻止生产者继续发送消息保护服务。 优化:监控内存、磁盘水位;限制生产速率;及时消费消息。
19. Spring AMQP 重要参数(面试高频)
生产必须配置 prefetch,很多人踩坑。
八、架构方案类面试题
20. RabbitMQ 三种投递模式
- At-most-once:最多一次(自动 ack,可能丢消息)
- At-least-once:至少一次(手动 ack,会重复消费,生产主流)
- Exactly-once:恰好一次,RabbitMQ 原生不支持,只能靠业务幂等间接实现。
21. 可靠消息最终一致性方案(分布式事务,结合 MQ)
本地消息表 / 事务消息(RocketMQ 支持,RabbitMQ没有事务消息) RabbitMQ 实现最终一致性方案:
重点区分:RocketMQ 有事务消息,RabbitMQ 不存在!不要混淆。




