消息的可靠性保证

1.面试题:Rabbitmq怎么保证消息的可靠性?

1.消费端消息可靠性保证

  1. 消息确认(Acknowledgements)

消费者在接收到消息后,默认情况下RabbitMQ会自动确认消息(autoAck=true)。为保证消息可靠性,可以设置autoAck=false,使得消费者在处理完消息后手动发送确认(basicAck)。如果消费者在处理过程中发生异常或者未完成处理就终止运行,那么消息在超时时间内将不会被删除,会再次被RabbitMQ投递给其他消费者。缺点:代码冗余多,容易出现死循环。

2.死信队列(Dead Letter Queue)

当消息不能被正常消费时(比如达到最大重试次数),可以通过设置TTL(Time To Live)或者死信交换器(Dead Letter Exchange)将消息路由至死信队列,从而有机会后续分析和处理这些无法正常消费的消息。(人工干预)

2.生产端消息可靠性保证:

  1. 消息持久化

当生产者发布消息时,可以选择将其标记为持久化(persistent).这意味着即使 RabbitMQ 服务器重启,消息也不会丢失,因为它们会被存储在磁盘上。

2.确认(Confirm)机制

开启confirm回调模式后,RabbitMQ会在消息成功写入到磁盘并至少被一个交换器接受后,向生产者发送一个确认(acknowledgement)。若消息丢失或无法投递给任何队列,RabbitMQ将会发送一个否定确认(nack). 生产者可以根据这些确认信号判断消息是否成功送达并采取相应的重试策略。

RabbitMQ作为消息中间件并启用publisher confirms(发布者确认)publisher returns(发布者退回)机制时,可以确保消息从生产者到交换机的投递过程得到更准确的状态反馈。

RabbitMQ消息确认机制

2. 发布者确认-Publisher Confirms

作用: Publisher Confirm机制允许RabbitMQ服务器通知生产者一个消息是否已经被交换机正确接收。当publisher-confirm-type设置为CORRELATED时,RabbitMQ会向生产者发送确认或否定响应,确认消息已到达交换机,但不保证消息已被路由到至少一个队列中。

生产者到交换机的确认(消息到达交换机)

2.1.配置:

spring.rabbitmq.publisher-confirm-type = CORRELATED

2.2. 代码实现

只要到达交换机就会触发

  public void sendMessage(String message) {
        // 创建一个关联ID,用于跟踪消息
        CorrelationData correlationId = new CorrelationData("message-id");

        // 设置确认回调
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                System.out.println("Message with id " + correlationData.getId() + " is acknowledged.");
            } else {
                System.out.println("Message with id " + correlationData.getId() + " failed to be acknowledged. Cause: " + cause);
            }
        });

     

        // 发送消息
        rabbitTemplate.convertAndSend("exchange-name", "routing-key", message, correlationId);
    }

3.发布者退回-Publisher Returns

作用: Publisher Return机制用于当消息无法按照路由键规则路由到任何队列时,或者由于其他原因(例如队列满、消息过大等)而被交换机拒绝时,RabbitMQ将消息返回给生产者。

交换机到队列的确认(消息是否正常发送到了其中任何一个队列)

通过实现 ReturnCallback 接口,发送消息失败返回,比如交换机路由不到队列时触发回调:

1.只有消息没有路由到队列的时候,才触发该回调 .

2.只要有一个队列接受到消息了,它就认为成功.

3.1 配置

spring.rabbitmq.publisher-returns = true

3.2 代码实现

  public void sendMessage(String message) {
       
  
        // 设置退回回调
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            System.out.println("Message was returned: " + new String(message.getBody()));
            System.out.println("Reply code: " + replyCode);
            System.out.println("Reply text: " + replyText);
            System.out.println("Exchange: " + exchange);
            System.out.println("Routing key: " + routingKey);
        });

        // 发送消息
        rabbitTemplate.convertAndSend("exchange-name", "routing-key", message);
    }

4.完整代码

   public void send(OrderingOk msg)
    {
        // 设置确认回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 确认消息是否被交换机接收。
             *
             * @param correlationData 包含消息相关数据的对象,用于识别消息的唯一性。
             * @param ack 表示消息是否被交换机确认接收。
             * @param cause 如果消息未被接收,提供未接收的原因。
             */
            @Override //线程B
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if(ack){
                    //该订单状态  10 -> 20
                    String id = correlationData.getId();
                    // 通过这个id改订单状态

                } else {
                    log.error("{]",cause);
                }
            }
        });
        // 设置退回回调, 之后投递失败的时候才会触发
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             * 记录被交换机退回的消息信息。
             *
             * @param message 消息对象,包含消息体。
             * @param replyCode 返回的响应代码,用于指示退回的原因。
             * @param replyText 返回的响应文本,提供关于退回的详细信息。
             * @param exchange 退回时涉及的交换机名称。
             * @param routingKey 退回时使用的路由键。
             */
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {

                System.out.println("Message was returned: " + new String(message.getBody()));
                System.out.println("Reply code: " + replyCode);
                System.out.println("Reply text: " + replyText);
                System.out.println("Exchange: " + exchange);
                System.out.println("Routing key: " + routingKey);
            }
        });
        //CorrelationData 创建一个关联数据,用于消息的跟踪,大部分都是业务单据的id
        CorrelationData correlationData = new CorrelationData("201408145676676");
        rabbitTemplate.convertAndSend("ordering_ok","",msg,correlationData);

    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这孩子叫逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值