MQ 服务端的可靠性
问题背景
默认情况下,RabbitMQ 收到消息优先放在内存,降低收发延迟。带来两个问题:
- MQ 宕机重启,内存中的消息直接丢失(
docker restart mq复现) - 内存容量有限,消费者故障 / 消费慢,消息大量积压,触发 pageout,MQ 会阻塞。 MQ 底层会把老旧消息刷到磁盘释放内存,但刷盘过程会阻塞 MQ。
解决方案:数据持久化 + Lazy Queue
1. 数据持久化
RabbitMQ 持久化分为三部分:
- 交换机持久化
- 队列持久化(默认 durable)
- 消息持久化:发送消息设置
delivery_mode = 2- delivery_mode=1:临时消息,存在内存,重启丢失
- delivery_mode=2:持久消息,写入磁盘
特点:开启生产者确认后,持久化需要等待磁盘写入完成才返回 ACK,速度会变慢;但不会出现 pageout 阻塞问题。
2. Lazy Queue(惰性队列)
- 3.6 版本引入;3.12 版本之后,所有队列默认都是 LazyQueue
- 机制:消息到达队列后直接存入磁盘,不优先放内存;消费者消费时才从磁盘加载到内存
- 优势:支持百万级海量消息堆积,写盘性能高,避免 pageout 阻塞问题
RabbitMQ 如何保证消息的可靠性总结
- 首先通过配置可以让交换机、队列、以及发送的消息都持久化。这样队列中的消息会持久化到磁盘,MQ 重启消息依然存在。
- RabbitMQ 在 3.6 版本引入了 LazyQueue,并且在 3.12 版本后会称为队列的默认模式。LazyQueue 会将所有消息都持久化。
- 开启持久化和生产者确认时,RabbitMQ 只有在消息持久化完成后才会给生产者返回 ACK 回调。