Rabbitmq消息可靠性

一、Rabbitmq生产者-----》交换机-----routingkey----》队列《-------消费者,这中间有几个地方存在因网络会服务器宕机原因导致消息丢失,如何保证消息可靠,至关重要!

  1. exchange、queue和message是持久化的
  2. confirm和return机制
  3. 手动ack确保消息被消费
  4. 当消息积压时,加入死信队列

详解和实战:

1、首先必须设置exchange和queue的属性durable为true:

 @Bean
    public TopicExchange topicExchange() {
        TopicExchange exchange = ExchangeBuilder.topicExchange(TOPIC_PLACE_ORDER_EXCHANGE).durable(true).build();
        //rabbitAdmin.declareExchange(exchange);
        return exchange;
    }

    @Bean
    public Queue userQueue() {
        return QueueBuilder.durable(USER_QUEUE).build();
    }

2、消息一定要送达exchange,开启confirm机制:

如何保证消息一定能从生产者发送到exchange,请参考 CSDN 中Publisher Confirm通讯模式的原生实现,下面介绍集成Springboot的实现:

(1)配置文件开启消息确认:

spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
  application:
    name: example
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    publisher-confirm-type: correlated     #开启消息确认

从源码中可以看出,消息确认类型有三种:

SIMPLE:代表单条或批量消息同步确认

CORRELATED: 与回调函数一起使用,实现异步消息确认

NONE:不确认

(2)编写回调函数:

rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if(!ack){
                System.out.println("====消息发送失败,重试!====");
            }
        });

通过查看源码:setConfirmCallback需要传递一个ConfirmCallback对象实例,使用lamda表达式实现即可

3、开启return机制:消息从exchang通过routingkey将消息路由到queue,也可能会发生消息的丢失,Rabbitmq使用Return机制来确保消息能从exchange路由到queue:

(1)编写配置文件,开启return机制:

spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
  application:
    name: example
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    publisher-confirm-type: correlated  #开启消息确认
    publisher-returns: on               # 可以写on/off,或者true/false

(2)编写回调函数:

 //只要调用了该方法,说明exchange在路由消息到queue时,失败了
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            System.out.println("===消息发送失败,进行补救====");
        });

3、服务器重启,queue里面的消息不会丢失

注意:在channel.queueDeclear()方法中的durable参数,指的当Rabbitmq重启的时候,queue不会丢失,而不是queue里面的消息不会丢失,当前我们需要讨论的是queue里面的消息,不丢失:

如何设置发送的消息持久化:通过MessagePostProcessor实例传递一个消息持久化的标识:

//配置消息持久化标识
        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                return message;
            }
        };
        //只会匹配第二个队列,#是通配符,可以有多个.
        rabbitTemplate.convertAndSend(SpringbootRabbitmqConstant.TOPIC_EXCHANGE, "111.222.aaa.bbb.ccc", msg, messagePostProcessor);

4、消费者获取队列消息不会丢失(手动ack)

(1)编写配置文件

spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
  application:
    name: example
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    publisher-confirm-type: correlated  #开启消息确认
    publisher-returns: on    # 可以写on/off,或者true/false
    listener:
      direct:
        acknowledge-mode: manual     # 设置手动ack,none表示不ack,auto表示自动ack

(2)在消费者@RabbitListener中,执行完成后手动ack:

  @RabbitListener(queues = SpringbootRabbitmqConstant.FANOUT_QUEUE + "1", ackMode = "AUTO")
    public void recoverMessage1(String msg, Message message, Channel channel) throws IOException {
        long deliveryTag = 0;
        try {
            byte[] body = message.getBody();
            msg = new String(body, StandardCharsets.UTF_8);

            deliveryTag = message.getMessageProperties().getDeliveryTag();
            System.out.println("recoverMessage1============" + msg + "deliveryTag:" + deliveryTag);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            //手动ack
            channel.basicAck(deliveryTag, false);
        }
    }

5、死信队列:

当队列中的消息达到预设阈值时,再发过来的消息会被删除,导致消息丢失;

引入死信队列,将消息发送到死信队列中,保证消息不丢失;

6、搭建Rabbitmq高可用,配置镜像队列进行备份,除非所有节点都挂掉才会消息丢失,虽然不能保证100%可靠,但比不配置,可靠性高很多,一般生产环境建议使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值