Rabbitmq消息可靠投递和重复消费等问题解决方案

本文详细探讨了RabbitMQ中确保消息可靠投递的各种策略,包括生产者端的事务和确认机制,如事务模式、普通确认模式、批量确认和异步确认。此外,还介绍了消息路由失败的处理方式,如ReturnListener和备用交换器。消费者端的确认机制和消息补偿策略也被提及,以应对消费者未成功处理消息的情况。最后,讨论了消息幂等性和最终一致性的重要性。
消息的可靠性投递

在一些对数据一致性要求较高的业务场景里面,如果消息在发布和消费过程中出现了问题(消息丢失,消息重复消费),就会导致数据不一致,要做到消息的可靠性投递。

在RabbitMq里面提供了很多保证消息可靠投递的机制,这也是RabbitMq的一个特性。
我们在讲可靠性投递的时候,必须要明确一个问题,因为效率与可靠性是无法兼得的,如果要保证每一个环节都成功,势必会对消息的收发效率造成影响。所以如果是一些业务实时一致性要求不是特别高的场合,可以牺牲一些可靠性来换取效率。

RabbitMq的功能模型:
在这里插入图片描述
有四个环节可能会导致消息出现问题。下面讲每个环节及其解决方案。

环节一:

消息从生产者发送到Broker,因为一个客观因素,比如网络问题,Broker问题导致消息可能没有发送到Broker中,生产者要确保知道消息是否成功发送到Broker上才行。

Rabbitmq提供了两种服务端确认机制来通知生产者消息是否发送到Broker成功,也就是生产者发送消息给RabbitMq服务端的时候,服务端会以某种方式应答生产者,只要生产者收到了这个应答,就代表消息发送到Broker成功。

第一种机制是事务模式:
我们通过一个 channel.txSelect()的方法把信道设置成事务模式,然后就可以发布消息给 RabbitMQ 了,如果 channel.txCommit();的方法调用成功,就说明事务提交成功,则消息一定到达了 RabbitMQ 中。
如果在事务提交执行之前由于 RabbitMQ 异常崩溃或者其他原因抛出异常,这个时候我们便可以将其捕获,进而通过执行 channel.txRollback()方法来实现事务回滚。

java原生API的实现:

public class TransactionProducer {
   
   

    public static void main(String[] args) throws Exception {
   
   
        ConnectionFactory factory = new ConnectionFactory();
        factory.setUri("amqp://guest:guest@192.168.18.140:5672");
        factory.setVirtualHost("/");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        //开启事务模式
        channel.txSelect();
        String message = "txtest";
        try {
   
   
            //发送消息
            channel.basicPublish("TransactionEx","TransactionMsg",false,false,null,message.getBytes());
            //int a = 1/0;
            //正常提交
            channel.txCommit();
            System.out.println("发送消息提交成功");
            //接下正确的业务逻辑
        }catch (Exception e){
   
   
            //出现异常,回滚消息,即使消息已经成功发送到Broker,也会回滚删除
            channel.txRollback();
            System.out.println("出现异常,回滚");
            //可以做一些补偿措施,比如重发等
        }
    }
}

流程
在这里插入图片描述

现象,正常提交,队列会出现相应消息,异常回滚,队列没有出现相应消息。
弊端:
在事务模式下,只有收到了服务端的Commit-OK指令,才能提交成功,所以可以解决生产者和服务端确认的问题,但是事务模式有一个缺点,他是阻塞服务端的,一条消息没有发送完毕,就不能发送下一条消息,会榨干RabbitMq服务器的性能,所以不建议生产环境使用。官方说会降低250倍性能。

第二种机制是确认机制:
确认模式分为三种:

  • 普通确认模式:在生产者这边通过调用channel.confirmSelect方法将信道设置为Confirm模式,然后发送消息,一旦消息被投递Broker后,Rabbitmq就会发送一个确认的Basic.Ack给生产者,也就是调用channel.waitForConfirms方法返回true,这样生产者就知道消息被服务端接收了。

java原生API的实现:

public class CommonConfirm {
   
   

    public static void main(String[] args) throws Exception{
   
   
        ConnectionFactory factory = new ConnectionFactory();
        factory.setUri("amqp://guest:guest@192.168.18.140:5672");
        factory.setVirtualHost("/");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.confirmSelect();
        String message = "commonConfirmTest";
        channel.basicPublish("TransactionEx","TransactionMsg",false,false,null,message.getBytes());
        //等待确认,也可以设置超时,也有个重载方法不设置超时时间的
        try {
   
   
            if (channel.waitForConfirms(5000)){
   
   
                //返回true的话确认发送成功
                System.out.println("发送成功");
            }else {
   
   
                System.out.println("发送失败");
            }
        }catch (Exception e){
   
   
            System.out.println("确认超时");
            //但是可能发送成功的情况,要做点补偿才行
        }

    }
}

但是这个是一条一条的发送确认,等待确认的过程中时阻塞的,所以这种方式会阻塞客户端,效率也不会太高。

批量确认:就是在开启Confirm模式后,先发送一批消息,然后再批量确认,使用的是channel.waitForConfirmsOrDie方法,如果方法没有抛出异常,就代表消息都被服务端接受了。

java原生API的实现:

public class BatchConfirm 
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值