RabbitMQ学习笔记(下):延迟队列,发布确认高级,备份交换机

news2025/1/21 5:54:40

十、延迟队列

延迟队列

概念:

延迟队列使用场景:

 

流程图:

延迟队列整合Springboot

导入依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.2</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.amqp</groupId>
			<artifactId>spring-rabbit-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

在java/com/atguigu/rabbitmq下创建config创建类SwaggerConfig,写入代码:

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
           .groupName("webApi")
           .apiInfo(webApiInfo())
           .select()
           .build();
    }
    private ApiInfo webApiInfo() {
        return new ApiInfoBuilder()
           .title("rabbitmq接口文档")
           .description("本文档描述了rabbitmq微服务接口定义")
           .version("1.0")
           .contact(new Contact("enjoy6288","http://atguigu.com","1551388580@qq.com"))
           .build();
    }
}

队列TTL代码框架图:

队列TTL(配置类代码):

@Configuration
public class TtlQueueConfig {
    //普通交换机的名称
    public static final String X_EXCHANGE = "X";
    //死信交换机的名称
    public static final String Y_DEAD_LETTER_EXCHANGE = "Y";
    //普通队列的名称
    public static final String QUEUE_A = "QA";
    public static final String QUEUE_B = "QB";
    //死信队列的名称
    public static final String DEAD_LETTER_QUEUE = "QD";
    //声明xExchange
    @Bean("xExchange")
    public DirectExchange xExchange(){
        return new DirectExchange(X_EXCHANGE);
    }
    //声明yExchange
    @Bean("yExchange")
    public DirectExchange yExchange(){
        return new DirectExchange(Y_DEAD_LETTER_EXCHANGE);
    }
    //声明普通队列A的TTL为10s
    @Bean("queueA")
    public Queue queueA(){
        Map<String,Object> arguments = new HashMap<>(3);
        //设置死信交换机
        arguments.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key","YD");
        //设置TTL
        arguments.put("x-message-ttl",10000);
        return QueueBuilder.durable(QUEUE_A).withArguments(arguments).build();
    }
    //声明普通队列B的TTL为40s
    @Bean("queueB")
    public Queue queueB(){
        Map<String,Object> arguments = new HashMap<>(3);
        //设置死信交换机
        arguments.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key","YD");
        //设置TTL
        arguments.put("x-message-ttl",40000);
        return QueueBuilder.durable(QUEUE_B).withArguments(arguments).build();
    }
    //死信队列
    @Bean("queueD")
    public Queue queueD() {
        return QueueBuilder.durable(DEAD_LETTER_QUEUE).build();
    }
    //绑定A-X
    @Bean
    public Binding queueABindingX(@Qualifier("queueA") Queue queueA,
                                 @Qualifier("xExchange") DirectExchange xExchange){
        return BindingBuilder.bind(queueA).to(xExchange).with("XA");
    }
    //绑定B-x
    @Bean
    public Binding queueBBindingX(@Qualifier("queueB") Queue queueB,
                                 @Qualifier("xExchange") DirectExchange xExchange){
        return BindingBuilder.bind(queueB).to(xExchange).with("XB");
    }
    //绑定D-y
    @Bean
    public Binding queueDBindingY(@Qualifier("queueD") Queue queueD,
                                  @Qualifier("yExchange") DirectExchange yExchange){
        return BindingBuilder.bind(queueD).to(yExchange).with("YD");
    }
}

队列TTL(生产者):

@Slf4j
@RestController
@RequestMapping("/ttl")
public class SendMsgController {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @GetMapping("/sendMsg/{message}")
    public void sendMsg(@PathVariable String message){
        log.info("当前时间:{},发送一条信息给两个TTL队列:{}",new Date().toString(),message);
        rabbitTemplate.convertAndSend("X","XA","消息来自ttl为10s的队列:"+message);
        rabbitTemplate.convertAndSend("X","XB","消息来自ttl为40s的队列:"+message);
    }
}

队列TTL(消费者)

@Slf4j
@Component
public class DeadLetterQueueConsumer {
    //接收消息
    @RabbitListener(queues="QD")
    public void receiveD(Message message, Channel channel) throws Exception{
        String msg = new String(message.getBody());
        log.info("当前时间:{},收到死信队列的消息:{}",new Date().toString(),msg);
    }
}

延迟队列优化

不能为需求增加队列,

写一个通用队列作为延迟队列:

配置类,在上面配置类中加入如下代码:

public static final String QUEUE_C = "QC";
//和死信交换机连接
@Bean("queueC")
public Queue queue(){
    Map<String,Object> arguments = new HashMap<>(3);
    //设置死信交换机
    arguments.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);
    //设置死信RoutingKey
    arguments.put("x-dead-letter-routing-key","YD");
    return QueueBuilder.durable(QUEUE_C).withArguments(arguments).build();
}
//和普通交换机绑定
@Bean
public Binding queueCBindingX(@Qualifier("queueC") Queue queueC,
                              @Qualifier("xExchange") DirectExchange xExchange){
    return BindingBuilder.bind(queueC).to(xExchange).with("XC");
}

在前面生产者的基础上写入如下代码: 

@Slf4j
@RestController
@RequestMapping("/ttl")
public class SendMsgController {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @GetMapping("/sendExpirationMsg/{message}/{ttlTime}")
    public void sendMsg(@PathVariable String message,@PathVariable String ttlTime){
        log.info("当前时间:{},发送一条时长{}毫秒TTL信息给队列QC:{}",
                new Date().toString(),ttlTime,message);
        rabbitTemplate.convertAndSend("X","XC",message,msg->{
            //发送消息的时候延迟时长
            msg.getMessageProperties().setExpiration(ttlTime);
            return msg;
        });
    }
}

点击启动类重新启动,在网页端输入:localhost:8080/ttl/sendExpirationMsg/你好1/20000和localhost:8080/ttl/sendExpirationMsg/你好2/2000。

问题:延迟队列是排队的,当队列中有多条消息时,延迟队列的消息会根据前面最长时间发送。

安装延迟队列插件:

在https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases下载rabbitmq_delayed_message_exchange插件,解压放置到RabbitMQ的插件目录。

rabbitmq的插件在:/usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins目录下,上传插件到目录下,如果上传失败用sudo rz先获得权限。

输入:rabbitmq-plugins enable rabbitmq_delayed_message_exchange

重启rabbitmq:systemctl restart rabbitmq-server

进入rabbitmq的交换机界面,查看下面是否出现,如果出现代表安装成功:

基于插件的延迟队列:

配置类

@Configuration
public class DelayedQueueConfig {
    //队列
    public static final String DELAYED_QUEUEE_NAME="delayed.queue";
    //交换机
    public static final String DELAYED_EXCHANGE_NAME="delayed.exchange";
    //routingKey
    public static final String DELAYED_ROUTING_KEY="delayed.routingkey";
    //声明队列
    @Bean
    public Queue delayedQueue(){
        return new Queue(DELAYED_QUEUEE_NAME);
    }
    //声明交换机,基于插件的
    @Bean
    public CustomExchange delayedExchange(){
        Map<String,Object> arguments = new HashMap<>();
        arguments.put("x-delayed-type","direct");
        //交换机名称,交换机类型,是否需要持久化,是否需要自动删除,其它参数
        return new CustomExchange(DELAYED_EXCHANGE_NAME,"x-delayed-message",true,false,arguments);
    }
    //绑定
    @Bean
    public Binding delayedQueueBindingDelayedExchange(@Qualifier("delayedQueue") Queue delayedQueue,
                                                      @Qualifier("delayedExchange") CustomExchange delayedExchange){
        return BindingBuilder.bind(delayedQueue).to(delayedExchange).with(DELAYED_ROUTING_KEY).noargs();
    }
}

生产者

//发消息,基于插件的消息及延迟时间
@GetMapping("/sendDelayMsg/{message}/{delayTime}")
public void sendMsg(@PathVariable String message,@PathVariable  Integer delayTime){
    log.info("当前时间:{},发送一条时长{}毫秒信息给延迟队列delayed.queue:{}",
            new Date().toString(),delayTime,message);
    rabbitTemplate.convertAndSend(DelayedQueueConfig.DELAYED_EXCHANGE_NAME,
            DelayedQueueConfig.DELAYED_ROUTING_KEY,message,msg->{
            //发送消息时延迟时间(毫秒)
                msg.getMessageProperties().setDelay(delayTime);
                return msg;
            });
}

消费者,创建DelayQueueConsumer类:

@Slf4j
@Component
public class DelayQueueConsumer {
    //监听消息
    @RabbitListener(queues = DelayedQueueConfig.DELAYED_QUEUEE_NAME)
    public void receiveDelayQueue(Message message){
        String msg = new String(message.getBody());
        log.info("当前时间:{},收到延迟队列的消息:{}",new Date().toString(),msg);
    }

}

测试:localhost:8080/ttl/sendDelayMsg/come on baby1/20000。localhost:8080/ttl/sendDelayMsg/come on baby2/2000

十一、发布确认高级

加入交换机或者队列两者有其中一者宕掉,消息都会丢失。

配置类:

生产者及消费者:

回调接口:

交换机确认

回退消息

十二、备份交换机

配置类:

结果分析:

幂性性:

使用场景:

代码实现:

十三、集群

惰性队列:

集群原理:

搭建集群:

镜像队列:

实现高可用负载均衡

十四、Federation

Exchange原理:

Exchange实现:

Queue实现:

Shovel:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1064056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SSM的电脑硬件库存管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

物联网AI MicroPython传感器学习 之 IR人体红外传感器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 热释电红外运动传感器能检测运动的人或动物身上发出的红外线&#xff0c;输出开关信号&#xff0c;可以应用于各种需要检测运动人体的场合。传统的热释电红外传感器需要人体热释电红外探头、专…

C++基础语法——unordered_map和unordered_set

1. unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到log(N)&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最好的查询是&#xff0c…

【16】c++设计模式——>建造者(生成器)模式

什么是建造者模式? 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许你构造复杂对象步骤分解。你可以不同的步骤中使用不同的方式创建对象&#xff0c;且对象的创建与表示是分离的。这样&#xff0c;同样的构建过程可以创建不同的表…

python pygame入门 - 安装测试篇

pygame入门 - 安装篇 引言一、安装测试1.1 创建虚拟环境1.2 安装测试pygame 二、查看例程源码2.1 源码位置2.2 简单修改 引言 pygame是Python语言特别为游戏开发而设计的一个开源库。它提供了一系列模块和函数&#xff0c;可以帮助开发者快速构建2D游戏、多媒体应用程序和其他…

Electronjs入门-Electron中的主要模块

在本节中&#xff0c;我们将了解在Electron中创建任何应用程序时的一些基本模块&#xff1b;这些模块多种多样&#xff0c;使我们能够轻松地进行进程通信&#xff0c;创建操作系统的本地菜单。 为了利用Electron模块&#xff0c;以及任何第三方或Node模块&#xff0c;不仅在主流…

10.3倒水问题(几何图论建模)

坐标图中每一个位置都对应一个合法的状态&#xff0c;BC对5升杯子做出限制&#xff0c;AD对9升杯子作出限制 每次倒水&#xff0c;都只能把目标杯子装满&#xff0c;否则无法确定倒出水的多少与目标杯子此时水的容量 所以例如&#xff0c;倒5升杯子时&#xff0c;只能要么把5…

盘点网安最好入手的10大岗位,就业转行必看

前言 前段时间&#xff0c;知名机构麦可思研究院发布了《2022年中国本科生就业报告》&#xff0c;其中详细列出近五年的本科绿牌专业&#xff0c;信息安全位列第一。 对于网络安全的发展与就业前景已经说过很多&#xff0c;它是收入较高的岗位之一&#xff0c;在转行领域也占…

IO流 之 打印流( PrintStream 和 PrintWriter )

打印流可以实现更加方便的打印数据出去&#xff0c;可以实现打印啥就是啥 PrintStream字节打印流 代码演示&#xff0c;将字符串和其他类型&#xff0c;打印到f.txt文件中。 package day0927;import java.io.FileNotFoundException; import java.io.PrintStream; import java…

伟大不能被计划

假期清理书单&#xff0c;把这个书读完了&#xff0c;结果发现出奇的好&#xff0c;可以说是值得亲身去读的书&#xff0c;中间的一些论述提供了人工智能专业方面的视角来论证这这个通识观点&#xff0c;可信度很不错&#xff1b; 这篇blog也不是对书的总结&#xff0c;更多的是…

LLMs 奖励剥削 RLHF: Reward hacking

让我们回顾一下你到目前为止所学到的内容。RLHF是一个微调过程&#xff0c;用于使LLM与人类偏好保持一致。在这个过程中&#xff0c;您利用奖励模型来评估LLM对提示数据集的完成情况&#xff0c;根据人类偏好指标&#xff08;如有帮助或无帮助&#xff09;进行评估。 接下来&…

软件设计开发笔记6:基于QT的Modbus RTU从站

Modbus是一种常见的工业系统通讯协议。在我们的设计开发工作中经常使用到它。作为一种主从协议&#xff0c;在上一篇我们实现了Mobus RTU主站工具&#xff0c;接下来这一篇中我们将简单实现一个基于QT的Mobus RTU从站工具。 1、概述 Modbus RTU从站应用很常见&#xff0c;有一…

山西电力市场日前价格预测【2023-10-07】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-10-07&#xff09;山西电力市场全天平均日前电价为422.87元/MWh。其中&#xff0c;最高日前电价为1500.00元/MWh&#xff0c;预计出现在18: 15-18: 45。最低日前电价为221.56元/MWh&#x…

【JavaEE】_HTTP请求与HTTP响应

目录 1. HTTP协议 2. HTTP请求 2.1 HTTP请求首行 2.2 URL 2.3 HTTP方法 2.3.1 GET请求 2.3.2 POST请求 2.3.3 GET与POST的区别 2.3.4 其他方法 2.4 请求报头header 2.4.1 Host&#xff1a; 2.4.2 Content-Length与Content-Type&#xff1a; 2.4.3 User-Agent&…

JavaScript系列从入门到精通系列第十七篇:JavaScript中的全局作用域

文章目录 前言 1&#xff1a;什么叫作用域 一&#xff1a;全局作用域 1&#xff1a;全局变量的声明 2&#xff1a;变量声明和使用的顺序 3&#xff1a;方法声明和使用的顺序 前言 1&#xff1a;什么叫作用域 可以起作用的范围 function fun(){var a 1; } fun();consol…

练[ZJCTF 2019]NiZhuanSiWei

[ZJCTF 2019]NiZhuanSiWei 文章目录 [ZJCTF 2019]NiZhuanSiWei掌握知识解题思路代码分析1代码分析2 关键paylaod 掌握知识 ​ data伪协议和php伪协议的使用&#xff0c;反序列化&#xff0c;代码审计&#xff0c;文件包含,file_get_contents函数绕过 解题思路 打开题目链接&…

【计算机操作系统慕课版】第二章:进程的控制与描述

注&#xff1a;博主斥巨资买到了2021版本慕课版的pdf 如果需要的话可以来私聊我哦~ 操作系统第二章知识点目录&#xff1a; 一、前言&#xff1a;前驱图与程序执行 1.1前驱图&#xff08;看箭头就行&#xff0c;名字高级&#xff0c;底层简单&#xff09; 1.2程序顺序执行 1…

Umijs介绍

今天我们来看 umijs 我们访问官网 https://umijs.org/ 这是一个可 插拔的企业级 React框架 当然 你也可以选择 React 的一个脚手架 但是 这样就有很多需要考虑的东西 用这个umi 很多点 我们就不需要考虑了 框架已经帮我们配置好了 这边 我们点击快速上手的一个 指南 我们可…

vue-img-cutter 实现图片裁剪[vue 组件库]

借助 vue-img-cutter 可以在网页端实现图片裁剪功能&#xff0c;最终功能效果如下&#xff1a; 组件 npm 安装 npm install vue-img-cutter2 --save-dev # for vue2 npm install vue-img-cutter3 --save-dev # for vue3vue-img-cutter使用 template模板标签模块&#xff0c…