RabbitMQ如何保证消息的可靠性

51 阅读2分钟

消息的生命周期

消息从生产端到消费端要经历四个过程:

  1. 生产者 -> 交换机
  1. 交换机 -> 队列
  2. 消息在队列上存储
  1. 队列 -> 消费者

这四个过程都有可能造成消息的丢失,所以要保证消息的可靠性就需要在这四个过程都对消息进行保护

Producer-to-Exchange

生产端投递的消息丢失的原因有很多,比如消息在网络中传输时发生丢失,或者RabbitMQ宕机了,丢失了不可怕,但是我们得知道消息丢失,以便进行消息重传。

RabbitMQ提供了confirm消息确认机制,消息到达Exchange后就会回调我们设置的ConfirmCallback函数返回Ack,如果未到达或者自身内部错误导致消息丢失则返回Nak,我们就可以通过返回值判断消息是否到达交换机

Exchange-to-Queue

如果消息到达了Exchange但无法将消息路由到队列有两种处理方式 回退消息、加入备份交换机

回退消息

回调ReturnCallback函数,告知生产者消息在从交换机转到队列的过程丢失了,并把消息的相关信息作为参数传递回来

备份交换机

在声明交换器(调用channel.exchangeDeclare方法)的时候添加alternate-exchange参数来指定备份交换机,当消息在主交换机找不到匹配队列时就会将消息发送给备份交换机

注意:

  • 如果同时配置了回调函数和备份交换机,则会使用备份交换机
  • 如果设置的 AE 不存在消息会丢失
  • AE上没有能与消息匹配的队列会造成消息丢失

Queue Sotrage

RabbitMQ的实现是基于内存的,如果RabbitMQ挂了,那重启后数据就丢失了,所以相关的数据应该持久化到磁盘中,就算RabbitMQ重启后也可以到硬盘中取数据恢复。需要给exchange、queue和message都进行持久化

Queue-to-Consumer

RabbitMQ 给提供了消费者应答(ack)机制,默认情况下这个机制是自动应答,消息推送到消费者就会自动 ack ,然后 RabbitMQ 删除队列中的消息。也可以启动手动应答,即手动确认回复ack后RabbitMQ才从队列中删除这条消息,若消息处理过程出现问题也可以回复nack拒收消息。

注意:

  • 回复Nack拒收消息需要设置是否重回队列,若设置为false则消息就丢失了
  • 若拒收时消息会被重回消息队列顶端,然而大部分情况报错并不会因为重试就能解决所以消息会不断被消费不断重回队列顶端

因此消费失败后将此消息存到 Redis,并记录日志等待手动处理