日常记录-SpringBoot整合RabbitMQ第三节(生产者ConfirmCallback和ReturnCallback)

参考以下博主的文章

RabbitMQ入门 安装 SpringAMQP简单队列、工作队列、发布订阅(扇出模式,广播模式)、Direct模式(Roting模式)、Topic模式

RabbitMQ(2)、MQ问题:消息可靠性、延迟消息( 延迟队列(插件 ))、消息堆积(惰性队列)、MQ的高可用。ConfirmCallback机制、ReturnCallback机制、死信交换机

我这里只会记录如何整合SpringBoot,安装和部署的具体详情可以看上面这位博主写的文章。

一、MQ解决什么问题

解决问题:实现异步、削峰、解耦

常见问题:

消息可靠性问题:如何确保消息被成功送达消费者,并且被消费者成功消费掉

延迟消息问题:如果一个消息,需要延迟15分钟再消费,像12306超时取消订单,如何实现消息的延迟投递
如果你的消息设置的延迟时间超过MQ的极限,消息会立刻给消费掉的。消息过期时间必须是非负32为整数,即:0<=n<=2^32-1,单位(毫秒) 。2^32-1=4294967295 约等于49天左右

消息堆积问题:如果消息无法被及时消费而堆积,如何解决百万级消息堆积的问题

MQ的高可用问题:如何避免MQ因为单点故障而不可用的问题

二、MQ的问题与解决方案

环节一 :生产者 -> 交换机
环节二 :交换机 -> 队列
环节三 : 队列 ->消费者
如果以上其中一个环节出了问题,消息就无法到达消费者

在这里插入图片描述

生产者发送消息可能出现的问题:

  1. 生产者发送的消息未送达交换机
  2. 生产者发送的消息到达交换机,但未到达队列

MQ收到消息后丢失的问题:

  1. MQ宕机,导致未持久化保存消息丢失
  2. 消费者接收消息后,尚未消费MQ就宕机

MQ对应的解决方案有以下:

  1. 生产者发送消息丢失:使用生产者确认机制
  2. MQ接收消息丢失:MQ消息持久化
  3. 消费者接收消息丢失:消费者确认机制与失败重试机制

三、生产者确认

生产者 -> 交换机 -> 队列
通过ConfirmCallback和ReturnCallback才能确认消息是否到达队列
在这里插入图片描述

1、ConfirmCallback(确认消息是否到达交换机)

application.yml添加配置publisher-confirm-type配置,确认机制异步还是同步,自己根据业务决定
在这里插入图片描述
模拟生产方确认消息是否到达交换机

import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ConfirmCallbackConfig {


    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void test(){
        //创建一个CorrelationData Correlation:关联
        CorrelationData correlationData = new CorrelationData();
        //设置消息的id
        correlationData.setId("msg-888888");
        //准备好 回调函数:Callback,用于接收 将来:Future 的确认结果
        correlationData.getFuture().addCallback(
                /**
                 * 当消息发送没有出现异常时,这个方法会被调用
                 */
                result -> {
                    if (result.isAck()){
                        System.out.println("发送消息成功,消息已到达交换机,消息id:"+correlationData.getId());
                    }else {
                        System.out.println("发送消息成功,消息没有到达交换机,消息id:"+correlationData.getId()+" 原因:"+result.getReason());

                    }                },
                /**
                 * 当消息发送出现异常时,这个方法会被调用
                 */
                ex -> {
                    System.out.println("发送消息异常,消息id:"+correlationData.getId()+" 异常:"+ex);
                }
        );
        //自己随便定一个没有的交换机
        rabbitTemplate.convertAndSend("xxxx.exchange", "demo", "到达交换机了吗",correlationData);
    }



}

名称为xxxx.exchange的交换机我没有
在这里插入图片描述
消息没有送达指定交换机
在这里插入图片描述
消息送达指定交换机
在这里插入图片描述在这里插入图片描述

2、ReturnCallback(确认消息是否到达队列)

application.yml新增ReturnCallback的配置,写在生产者这边,我生产者和消费者都是同一个服务

在这里插入图片描述
创建ReturnCallback配置类,统一管理

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class RabbitReturnCallBackConfig implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            //当交换机把消息路由到队列出现问题时,这个方法会自动执行
            log.warn("把消息路由到队列失败,replyCode{},replyText{},RoutingKey={},msg={}", replyCode,replyText,exchange,routingKey, message);
        });
    }


}

定义交换机、队列

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 需要:
 *      1. 声明Direct类型的交换机:direct.exchange
 *      2. 声明队列1:direct.queue1
 *         声明队列2:direct.queue2
 *      3. 把交换机与队列1绑定:把 RoutingKey为orange的消息 -> 投递到队列1
 *         把交换机与队列2绑定:把 RoutingKey为black的消息  -> 投递到队列2
 *         把交换机与队列2绑定:把 RoutingKey为green的消息  -> 投递到队列2
 *
 *                             ↗ RoutingKey = orange   ->  direct.queue1 -> C(消费者1)
 * P(生产者) -> direct.exchange
 *                             ↘ RoutingKey = black
 *                                                    ->  direct.queue2   -> C(消费者2)
 *                             ↘ RoutingKey = green
 *
 */
@Configuration
public class DirectQueueConfig {


    //定义direct类型交换机
    @Bean
    public DirectExchange directExchange() {
        return ExchangeBuilder.directExchange("direct.exchange").build();
    }


    //定义持久化队列
    @Bean
    public Queue directQueue1() {
        return new Queue("direct.queue1",true,false,false);
    }

    //定义持久化队列
    @Bean
    public Queue directQueue2() {
        return QueueBuilder.durable("direct.queue2").build();
    }

    //把交换机与队列direct.queue1绑定:把 RoutingKey为orange的消息,投递到队列direct.queue1
    @Bean
    public Binding directQueue1Binding(Queue directQueue1, DirectExchange directExchange) {
        return BindingBuilder.bind(directQueue1).to(directExchange).with("orange");
    }

    //把交换机与队列direct.queue2绑定:把 RoutingKey为black的消息,投递到队列direct.queue2
    @Bean
    public Binding directQueue2BindingInfo(Queue directQueue2, DirectExchange directExchange) {
        return BindingBuilder.bind(directQueue2).to(directExchange).with("black");
    }
    //把交换机与队列direct.queue2绑定:把 RoutingKey为green的消息,投递到队列direct.queue2
    @Bean
    public Binding direcQueue2BindingError(Queue directQueue2, DirectExchange directExchange) {
        return BindingBuilder.bind(directQueue2).to(directExchange).with("green");
    }



}

模拟生产者

import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ReturnCallBackTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //模拟生产者
    @Test
    public void test(){
        
        //rabbitTemplate.convertAndSend("direct.exchange","orange","这是orange");
        //rabbitTemplate.convertAndSend("direct.exchange","black","这是black");
        //rabbitTemplate.convertAndSend("direct.exchange","green","这是green");

        //没有绑定routingkey=xxxx的队列
        rabbitTemplate.convertAndSend("direct.exchange","xxxx","这是green");
    }
}

捕获到消息发送失败了
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot框架可以很容易地与RabbitMQ进行集成。为了实现这个目标,你需要在项目的依赖项中添加两个关键的依赖项。首先,你需要添加spring-boot-starter-amqp依赖项,它提供了与RabbitMQ进行通信的必要类和方法。其次,你还需要添加spring-boot-starter-web依赖项,以便在项目中使用Web功能。 在你的项目中创建两个Spring Boot应用程序,一个是RabbitMQ生产者,另一个是消费者。通过这两个应用程序,你可以实现消息的发送和接收。生产者应用程序负责将消息发送到RabbitMQ的消息队列,而消费者应用程序则负责从队列中接收并处理消息。这样,你就可以实现基于RabbitMQ的消息传递系统。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot整合RabbitMQ](https://blog.csdn.net/K_kzj_K/article/details/106642250)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Springboot 整合RabbitMq ,用心看完这一篇就够了](https://blog.csdn.net/qq_35387940/article/details/100514134)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [undefined](undefined)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值