RabbitMq如何确保消息不丢失

问题:在生产环境中由于一些不明原因,导致 rabbitmq 重启,在 RabbitMQ 重启期间生产者消息投递失败,导致消息丢失,需要手动处理和恢复。于是,我们开始思考,如何才能进行 RabbitMQ 的消息可靠投递呢? 特别是在这样比较极端的情况,RabbitMQ 集群不可用的时候,无法投递的消息该如何处理呢?

解决方案就是缓存,比如当生产者发送消息到交换机时,但交换机不存在,我们应该将消息放入缓存中;或者交换机存在,队列不存在了,当交换机发送不到队列中也应该将消息放入缓存。然后在缓存中配置一个定时任务,对没有发送成功的消息重新进行投递。这样就避免了消息丢失的情况。

回调接口------消息确认

接下来我们通过代码实现以上机制,架构图如下所示:我们要解决问题就是如果图中的交换机或者队列出现问题,应该将消息进行缓存处理,防止消息丢失,具体的实现就是通过生产者的回调接口ConfirmCallback来实现。

1️⃣ 修改配置文件

在配置文件当中需要添加配置表示开启发布消息成功到交换器后会触发回调方法

NONE:禁用发布确认模式,是默认值

CORRELATED:发布消息成功到交换器后会触发回调方法

SIMPLE:经测试有两种效果,其一效果和 CORRELATED 值一样会触发回调方法;其二在发布消息成功后使用 rabbitTemplate 调用 waitForConfirms 或 waitForConfirmsOrDie 方法等待 broker 节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是 waitForConfirmsOrDie 方法如果返回 false 则会关闭 channel,则接下来无法发送消息到 broker

👂这个层次是在交换机层次做的工作,保证消息被正确发送到了交换机。

通过实现一个RabbitTemplate.ConfirmCallback接口,将接口注入到RabbitTemplate中,当消息发送到交换机后就会触发这个回调。如果失败了可以考虑进入死信队列或者重新发送。但是做不到队列层面的工作。

复制代码
 /**
     * 交换机确认回调方法
     *
     * @param correlationData 保存回调消息的ID以及相关信息
     * @param ack             表示交换机是否收到消息(true表示收到)
     * @param cause           表示消息接收失败的原因(收到消息为null)
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack) {
            log.info("交换机已经收到ID为:{}的消息", id);
        } else {
            log.info("交换机还未收到ID为:{}的消息,原因为:{}", id, cause);
        }
    }
回调接口------消息回退

我们知道在仅开启了生产者确认机制的情况下,交换机接收到消息后,会直接给消息生产者发送确认消息,如果发现该消息不可路由,那么消息会被直接丢弃,但此时生产者是不知道消息被丢弃这个事件的。那么如何让无法被路由的消息能够让生产者感知并做出处理呢

我们可以通过设置 mandatory 参数可以在当消息传递过程中不可达目的地时将消息返回给生产者。

在配置文件当中需要添加配置表示开启消息路由失败后会触发消息回退回调方法

👂通过实现 RabbitTemplate.ReturnsCallback 接口

复制代码
    @Override
    public void returnedMessage(ReturnedMessage returned) {
        log.info("消息{}:,被交换机{}退回,退回原因:{},路由key:{}",
                new String(returned.getMessage().getBody()),
                returned.getExchange(),
                returned.getReplyText(),
                returned.getRoutingKey());
    }
备份交换机

前面我们提到交换机如果出现了问题接受不到消息,我们就让交换机进行消息确认,让生产者重新发消息。如果队列出问题收不到消息,我们就进行消息回退,也是让生产者重新发消息。此外,还有一种解决方法就是给交换机添加一个备份交换机,有了备份交换机之后可以不用讲消息回退给生产者,而是将无法投递的消息交给备份交换机,让备份交换机通过自己的路由以及自己的队列发送给消费者,这样也能达到一个消息不丢失的目的。并且这种方式还能建立一个报警队列,用独立的消费者进行监测和报警。

当回调函数和备用交换机一起使用的时候,备份交换机优先级高。

相关推荐
初次攀爬者1 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者3 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧4 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖4 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农4 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者4 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端
业精于勤_荒于稀4 天前
物流订单系统99.99%可用性全链路容灾体系落地操作手册
分布式
Ronin3054 天前
信道管理模块和异步线程模块
开发语言·c++·rabbitmq·异步线程·信道管理
Asher05094 天前
Hadoop核心技术与实战指南
大数据·hadoop·分布式
凉凉的知识库4 天前
Go中的零值与空值,你搞懂了么?
分布式·面试·go