MQ 核心知识点笔记
一、MQ 如何保证消息不丢失?
消息丢失可能发生在生产、存储、消费三个阶段,需从全链路保障:
-
生产者确认机制
RabbitMQ 的publisher-confirm
机制可避免消息发送阶段丢失。消息发送后,MQ 会返回确认结果(成功/失败),生产者可根据结果重试,确保消息能到达 MQ。 -
消息持久化
MQ 默认内存存储消息,宕机后会丢失,需开启三层持久化:- 交换机持久化:声明交换机时指定
durable=true
; - 队列持久化:声明队列时指定
durable=true
; - 消息持久化:消息属性中设置
DeliveryMode=PERSISTENT
(SpringAMQP 默认持久化)。
- 交换机持久化:声明交换机时指定
-
消费者确认与重试机制
- 开启消费者自动确认(
ack-mode=auto
),由 Spring 处理完成业务后自动发送 ACK,避免业务未处理完就确认导致的丢失; - 开启失败重试:配置重试次数(如 3 次),多次失败后投递到异常交换机,由人工介入处理。
- 开启消费者自动确认(
二、如何避免 MQ 消息重复消费?
重复消费通常因网络抖动、消费者宕机导致 MQ 未收到 ACK 而重发,核心是保证消费幂等性:
- 唯一标识:每条消息添加唯一 ID(如订单号),作为去重依据。
- 幂等方案:
- 分布式锁:消费前用 ID 获取锁,确保同一消息仅被一个消费者处理;
- 数据库锁:悲观锁(
select ... for update
)或乐观锁(版本号version
),避免重复更新数据。
三、RabbitMQ 死信交换机与延迟队列
1. 死信交换机(DLX)
当队列中的消息满足以下条件时,会成为“死信”:
- 消费者拒绝消费(
basic.reject
/basic.nack
)且requeue=false
; - 消息过期(TTL 结束未消费);
- 队列消息堆积满,最早的消息被挤出。
若队列配置了 dead-letter-exchange
属性,死信会被投递到指定交换机,即死信交换机,可用于后续处理(如失败消息归档)。
2. 延迟队列
定义:消息进入队列后,延迟一段时间才被消费的队列,适用于超时订单关闭、限时优惠失效、定时发布等场景。
实现方式:
- 基于死信 + TTL:队列设置 TTL(消息存活时间),消息过期后成为死信,通过死信交换机投递到目标队列被消费;
- 延迟队列插件(DelayExchange):声明交换机时指定
delayed=true
,发送消息时添加x-delay
头(毫秒数),更简单高效。
TTL 规则:消息的过期时间以“队列设置”和“消息自身设置”中较短的为准。
四、消息堆积在 MQ 如何解决?
消息堆积因生产者速度 > 消费者处理速度,解决方案从“提速消费”和“扩容存储”入手:
-
提高消费速度
- 增加消费者实例:通过集群部署消费者,分摊消费压力;
- 消费者内优化:使用线程池并行处理消息(需注意线程安全)。
-
扩大存储上限
- 使用惰性队列:消息直接存入磁盘(而非内存),消费时才加载到内存,支持百万级消息存储,适合堆积场景。
五、RabbitMQ 高可用机制
生产环境常用集群模式保证高可用,核心方案:
-
镜像队列
- 一主多从结构:主节点处理读写,从节点同步数据;
- 主节点宕机后,从节点自动切换为主(需注意:主从同步完成前宕机可能丢数据)。
-
仲裁队列(推荐)
- 基于 Raft 协议实现主从强同步,数据一致性更高;
- 声明队列时指定
x-queue-type=quorum
即可,无需额外配置,解决镜像队列的同步丢数据问题。
总结
以上为 MQ 核心面试点,重点掌握消息可靠性(不丢失、不重复)、死信/延迟队列的业务场景、堆积与高可用解决方案。实际回答时可结合项目案例(如“用延迟队列处理超时订单,基于死信 + TTL 实现”),体现落地能力。