核心思路:生产者 -> 交换机 Exchange -> 队列 Queue -> 消费者;AMQP 协议。
1.基础概念
Broker:RabbitMQ 服务实例,一个 Broker 包含多个 VirtualHost。
VirtualHost(vhost):虚拟主机,隔离资源(交换机、队列),可以分配权限,类似数据库的库。
Exchange 交换机:接收生产者消息,根据路由规则转发到队列。
Queue 队列:存储消息,等待消费者消费。
Binding 绑定:交换机和队列之间的绑定关系,绑定需要 routingKey。
RoutingKey 路由键:生产者发送消息携带,用来匹配绑定规则。
BindingKey 绑定键:绑定时指定,交换机根据 routingKey 匹配 bindingKey。
4 种交换机类型⭐高频
Direct(直连):routingKey 完全匹配 bindingKey,消息发送到对应队列。点对点场景。
Fanout(广播):忽略 routingKey,消息分发到所有绑定该交换机的队列。群发、通知场景。
Topic(主题):模糊匹配。
*匹配一个单词;#匹配 0 或多个单词。日志分类最常用。Headers:不使用 routingKey,通过消息 header 属性匹配,性能差,很少使用。
2.消息可靠(三大可靠性:生产者、Broker、消费者)
(1)生产者消息投递确认(保证消息成功到达 Broker)
Confirm 确认机制:生产者开启 publisher-confirm-type。消息到达 Broker 返回 ack;失败返回 nack。异步回调。
Return 退回机制:消息到达交换机,但是找不到匹配队列,消息退回生产者。
Confirm 保证消息成功抵达 exchange;Return 保证消息成功路由到 queue。
(2)Broker 持久化(宕机不丢消息)
交换机持久化:durable=true
队列持久化:durable=true
消息持久化:deliveryMode=2
三者都配置,消息写入磁盘。但刷盘是操作系统异步,极端断电仍可能丢失。
(3)消费者消息确认 ACK(防止消息丢失、重复消费)
自动 ACK(默认):消息分发成功就自动 ack。消费者还没处理完宕机 → 消息丢失,生产禁用。
手动 ACK:业务处理成功,调用
basicAck;处理失败:basicNack:拒绝,可以 requeue=true 重回队列;requeue=false 丢弃 / 转入死信。
basicReject:一次拒绝单条消息。
生产推荐手动 ACK。
3.死信队列 DLX(重点)
死信:消息无法被正常消费,变成死信。 触发死信条件:
消息被 nack,requeue=false
消息 TTL 过期
队列消息数量达到最大长度
DLX 原理:给普通队列绑定死信交换机;消息变成死信,自动转发到死信交换机,路由到死信队列。
适用场景:延时队列、失败消息归档重试。
RabbitMQ 没有原生延时队列,TTL+DLX 模拟延时队列;缺陷:队列过期,是在消息出队时检测,不是消息到期立刻转发。
4.消息重复消费(幂等)
MQ 无法避免重复投递(网络抖动,ack 丢失,Broker 重复推送)。
解决方案:业务端实现幂等
唯一消息 ID,数据库唯一索引
Redis 记录已消费消息 id
状态机,根据业务状态判断是否处理
口诀:MQ 不保证只投递一次,只能保证至少投递一次 at-least-once
5.消息堆积问题⭐面试高频
原因
消费者消费速度远低于生产速度;消费者宕机;消费逻辑阻塞。
解决方案
排查消费代码,优化消费逻辑,去掉慢 IO
增加消费者数量,提高消费能力(同一队列,多消费者轮询消费)
批量消费
堆积严重:临时扩容队列,分流;紧急场景可以丢弃无效消息
注意:不要盲目提高 prefetch。prefetch 是预取数量。
Prefetch(预取)
basicQos (prefetchCount),告诉 MQ 一次性预取 N 条消息给消费者,未 ack 前不再推送。 作用:流量控制,防止消费者一次性被压爆。
6.消息丢失全链路总结
生产者丢消息 → 开启 Confirm+Return Broker 丢消息 → 交换机、队列、消息持久化 消费者丢消息 → 关闭自动 ACK,使用手动 ACK
7.其他高频知识点
(1)集群模式
普通集群:消息只存在单个节点,其他节点仅元数据;访问其他节点会转发。
镜像队列(RabbitMQ3.8 后弃用):消息同步到多个节点,高可用。
仲裁队列 Quorum Queue(3.8 + 推荐):Raft 协议,数据多副本,替代镜像队列,高可用。
(2)消费模式
轮询:默认,消息均匀分给多个消费者
公平分发:配合 prefetch,谁处理完,给谁下一条
(3)事务
RabbitMQ 支持生产者事务(channel.txSelect),性能极差,生产几乎不用;优先 Confirm。
高频深挖面试题
Q1:AMQP 和 Kafka 的协议区别?
RabbitMQ AMQP 是应用层协议;Kafka 自定义二进制协议。AMQP 面向消息投递可靠性,Kafka 面向高吞吐。
Q2:为什么不推荐用事务,改用 Confirm?
事务同步阻塞,性能差;Confirm 异步回调,吞吐量更高。
Q3:死信队列 TTL 两种设置方式?
消息级别 TTL(每条消息单独过期时间);队列级别 TTL(队列内所有消息统一过期)。队列 TTL 更推荐。
Q4:什么是 At most once / At least once / Exactly once?
At most once:最多一次,可能丢消息(自动 ack) At least once:至少一次,可能重复(手动 ack,生产常用) Exactly once:恰好一次,MQ 做不到,业务幂等实现。
Q5:仲裁队列和镜像队列区别?
镜像队列全节点同步,性能差,3.8 废弃;仲裁队列基于 Raft,少数副本不可用仍可读,性能更好。
一句话背诵总结
RabbitMQ 基于 AMQP;4 种交换机 Direct/Fanout/Topic/Headers;
消息可靠性分生产者 Confirm、Broker 持久化、消费者手动 ACK;
死信队列 DLX 处理过期 / 拒绝消息;
MQ 只能保证至少投递一次,业务实现幂等解决重复消费;
消息堆积优化消费能力,Quorum 仲裁队列作为高可用方案。