RabbitMQ(消息队列)

RabbitMQ

它是消息中间件,是在消息的传输过程中保存消息的容器,实现应用程序和应用程序之间通信的中间产品。目前主流消息队列通讯协议是AMQP(二进制传输,支持多种语言)、JMS(HTTP传输,只支持Java)。

特点:每秒十万左右级别、消息延迟在微秒级、完整的消息确认机制、并发能力强、性能好。

常见MQ

  • ActiveMQ基于JMS,每秒数万级别
  • RabbitMQ基于AMQP,每秒十万级别
  • RocketMQ是阿里的产品,基于JMS,每秒十万级别,经历过双十一
  • Kafka自定义协议,每秒百万级别

体系结构

分为:服务器、交换器、队列;

服务器:负责管理所有的交换器和队列,一个RabbitMQ内有多个服务器,(为了避免每次发送消息都建立TCP连接,有了很多的服务器,每个线程建立单独的服务器进行通讯)每个服务器负责一部分交换器和队列,之间通过 HTTP 协议通信;

交换机:负责接收、路由、传递消息,支持多种交换器类型,每个类型有不同的消息传递方式和使用场景;

队列:负责存储消息,支持多种队列,都有不同的存储方式;

安装:

使用docker方式

# 拉取镜像
docker pull rabbitmq:3.8.12-management
# 注意:在拉取镜像,遇到missing signature key问题,需要提升docker的版本

# 运行容器
# -d 参数:后台运行 Docker 容器
# -e 参数:设置容器内的环境变量,这里我们设置了登录RabbitMQ管理后台的默认用户和密码
docker run --name rabbitmq -d -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=123456 rabbitmq:3.8.12-management

# 启动成功,MQ的客户端页面,输入所设置的用户名和密码
# 访问:http://xxx:15672

# 如果访问不通,需要开放端口
firewall-cmd --zone=plublic -add-pord=5672/tcp --add-pord=15672/tcp --permanent
success
firewall-cmd --reload
success

发送消息

需要引包

<dependency>
     <groupId>com.rabbitmq</groupId>
     <artifactId>amqp-client</artifactId>
     <version>5.20.0</version>
</dependency>

生产者

// 生产者 - 产生消息
public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("IP地址");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("123456");
    // 创建连接
    Connection connection = connectionFactory.newConnection();
    // 创建频道
    Channel channel = connection.createChannel();
    // 创建队列,参数:队列名称、是否定义持久化队列、是否独占本次连接、是否在不使用的时候自动删除队列、其他参数
    channel.queueDeclare("new_queue", true, false, false, null);
    String message = "发送的消息的内容:123";
    // 参数:交换机名称,默认Default Exchange、队列名称、配置信息、消息内容
    channel.basicPublish("", "new_queue", null, message.getBytes());
    // 关闭资源  
    channel.close();
    connection.close();
}

创建一个队列,并有消息待查看,点击该队列的名称,在Get messages处,可以查看该消息的信息;

查看队列:

在这里插入图片描述
在这里插入图片描述
消费者

// 消费者 - 要消费消息
public static void main(String[] args) throws Exception {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("IP地址");
    factory.setPort(5672);
    factory.setVirtualHost("/");
    factory.setUsername("guest");
    factory.setPassword("123456");
    // 创建连接 Connection        
    Connection connection = factory.newConnection();
    // 创建频道  
    Channel channel = connection.createChannel();
    // 接收消息  
    DefaultConsumer consumer = new DefaultConsumer(channel) {
        // 回调方法,当收到消息后,会自动执行该方法  
        // 参数:标识、获取一些信息,交换机等、配置信息、数据(消息内容)
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("consumerTag:" + consumerTag);
            System.out.println("Exchange:" + envelope.getExchange());
            System.out.println("RoutingKey:" + envelope.getRoutingKey());
            System.out.println("properties:" + properties);
            System.out.println("body:" + new String(body));
        }
    };
    // 监听程序,用来监听消息,参数:队列、是否自动确认、回调对象  
    channel.basicConsume("new_queue", true, consumer);
}

如果有被消费者消费,会在管理页中,该队列的 Ready进行-1;

工作模式

简单模式

生产者(只有一个)、消费者(只有一个)、消息储存在队列中;

工作队列模式

生产者(只有一个)、消费者(有多个)、消息储存在队列中;消费者谁抢到算谁的。

发布订阅模式

生产者(只有一个)、消费者(有多个)、交换机、多个队列;

生产者把消息发送给交换机,交换机处理消息取决于交换机的类型,交换机根据类型把消费存在对应的队列中,消费者(多个)满足规则都可以得到消息;

交换机有3种类型

➢ Fanout:广播,将消息交给所有绑定到交换机的队列

➢ Direct:定向,把消息交给符合指定routing key 的队列

➢ Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

路由模式

队列与交换机的绑定,使用Direct,消费者监听的队列,该队列与交换机绑定的路由件匹配,该消费者可以收到消息。其他消费者也监听该队列,但路由件不匹配,不会收到消息。

查看交换机

在这里插入图片描述

交换机与队列的绑定

在这里插入图片描述
在这里插入图片描述

主题模式(通配符匹配)

这个与路由模式类似,只是这个支持通配符绑定,# 匹配一个或多个词,* 匹配不多不少恰好1个词。

创建

创建交换机

在这里插入图片描述

创建队列

在这里插入图片描述

队列与交换机绑定

在这里插入图片描述

整合SpringBoot

引包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

更改配置文件

spring: 
  rabbitmq: 
    host: IP地址
    port: 5672 
    username: guest 
    password: 123456 
    virtual-host: /
    # 来保证消息的可靠性
    publisher-confirm-type: CORRELATED # 交换机的确认
    publisher-returns: true # 队列的确认

代码

// 生产者
@Autowired  
private RabbitTemplate rabbitTemplate;
  
public void testSend() {  
    rabbitTemplate.convertAndSend("交换机","路由键","消息内容");  
}  
// 消费者 (durable 是否持久化)
@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "队列名字", durable = "true"),
            exchange = @Exchange(value = "交换机"),
            key = {"路由键"}
))
public void process(String dateString,Message message,Channel channel) {
    log.info("消息内容:"+ dateString);
}

配置类

生产者保障消息的可靠性

生产者 - 保障消息是否发送到队列或者交换机

@Component
public class MQAckConfig 
    implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }

    /**
     * 确认消息是否发送到交换机
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            log.info("消息发送到交换机 - 成功!数据:" + correlationData);
        } else {
            log.info("消息发送到交换机 - 失败!数据:" + correlationData + " 原因:" + cause);
        }
    }

    /**
     * 确认消息是否发送到队列 - 只有发送失败的时候才会调用该方法
     */
    @Override
    public void returnedMessage(ReturnedMessage returned) {
        log.info("消息主体: " + new String(returned.getMessage().getBody()));
        log.info("应答码: " + returned.getReplyCode());
        log.info("描述:" + returned.getReplyText());
        log.info("消息使用的交换器 exchange : " + returned.getExchange());
        log.info("消息使用的路由键 routing : " + returned.getRoutingKey());
    }

}

消费者保障消息的可靠性

消费者 - 保障消息真的收到,改为手动确认ACK

spring:
  rabbitmq:
    ...
    listener:
      simple:
        acknowledge-mode: manual # 把消息确认模式改为手动确认

消费者手动ACK

@RabbitListener( 
    // 设置绑定关系
    bindings = @QueueBinding(
        // 配置队列信息:durable 设置为 true 表示队列持久化;autoDelete 设置为 false 表示关闭自动删除
        value = @Queue(value = QUEUE_NAME, durable = "true", autoDelete = "false"),
        // 配置交换机信息:durable 设置为 true 表示队列持久化;autoDelete 设置为 false 表示关闭自动删除
        exchange = @Exchange(value = EXCHANGE_DIRECT, durable = "true", autoDelete = "false"),
        // 配置路由键信息
        key = {ROUTING_KEY}
))
public void processMessage2(String dataString, Message message, Channel channel) throws IOException {
    // 注意: 重置消息,需要考虑幂等性
    long tag = message.getMessageProperties().getDeliveryTag();
    try {
        log.info("消费者 - 接收消息:" + dataString);
        // System.out.println(10 / 0);  // 手动制造出异常,让消息回到队列中
        channel.basicAck(tag, false);
    } catch (Exception e) {
        // 获取信息,查看此消息是否曾经被投递过
        Boolean redelivered = message.getMessageProperties().getRedelivered();
        if (!redelivered) {
            // 没有被投递过,那就重新放回队列,重新投递,再试一次
            channel.basicNack(tag, false, true);
        } else {
            // 已经被投递过,且这一次仍然进入了 catch 块,那么返回拒绝此消息,不会回到MQ队列中
            channel.basicReject(tag, false);
        }
    }
}

消费者-限流

大量消息进入队列中,消息队列中消息有1万,设置每次最多从队列取回1000个消息,并发能力只能处理1000个请求,消费端-最多只处理1000个请求;

限流配置

spring:
  rabbitmq:
    ...
    listener:
      simple:
        acknowledge-mode: manual # 把消息确认模式改为手动确认
        prefetch: 10  # 设置消费者,每次最多从消息队列服务器取回多少消息,并不是一下把队列中的消息全部取走

从队列中Ready,变成所设置的值,从此起到了限流的作用,消息者处理ACK个数也下降。

在这里插入图片描述

消息超时

可在创建队列的时候,设置参数:x-message-ttl = 3000 (毫秒值),当我们生产者发送消息到队列,队列里的消息没有被消费者消费时,可通过队列里的消息超时时间,进行丢弃消息。

@Autowired
private RabbitTemplate rabbitTemplate;

MessagePostProcessor processor = (Message message) -> {
    // 设定超时时间,单位 (毫秒)
    message.getMessageProperties().setExpiration("7000");
    return message;
};
rabbitTemplate.convertAndSend("交换机名", "路由键", "生产者发送消息 - 消息超时 - " + processor);

死信

一个消息无法被消费,会变成死信;产生的原因:消费者拒绝:basicNackbasicReject这两个方法不把消息重新放回队列、队列溢出:队列里的消息达到数量的限制、消息超时:超时时间未被消费;

解决:丢弃(一般不重要数据)、入库(记录日志、后续处理)、监听(进入死信队列,监听死信队列进行处理)

前提准备:

创建死信交换机、死信队列、死信路由键,互相绑定;

创建正常交换机、队列、路由键,互相绑定;
在这里插入图片描述

// 前提把 死信、正常都创建好,绑定好
// 监听正常队列
@RabbitListener(queues = {‘正常队列’})
public void processMessageNormal(String dateString, Message message, Channel channel) throws IOException {
    // 监听正常队列,但是拒绝消息,进行消息拒绝
    log.info("【正常】接受到消息:" + dateString);;
    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
}
// 监听死信队列
@RabbitListener(queues = {‘死信队列’})
public void processMessageDead(String dataString, Message message, Channel channel) throws IOException {
    // 监听死信队列
    log.info("【死信】接受到消息 = " + dataString);
    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}

延迟队列

方案一:

生产者发送消息,到队列中,该队列配置消息超时时间,并没有消费者进行监听该队列(进行监听消费),超时进入死信队列,(监听死信队列)就是延迟队列的一种配置。

方案二:

安装插件,默认消息存放最多2天

地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange

下载插件的网址:https://www.rabbitmq.com/community-plugins.html

事务

该事务处理仅仅在java层面,生产者1发送消息,生产者2发送消息,保障其中有一个发送失败,都要失败,需要添加配置类:

@Configuration
@Data
public class RabbitConfig {

    @Bean
    public RabbitTransactionManager transactionManager(CachingConnectionFactory connectionFactory) {
        return new RabbitTransactionManager(connectionFactory);
    }

    @Bean
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setChannelTransacted(true);
        return rabbitTemplate;
    }
}

惰性队列

一般队列创建是默认,并不是惰性队列,惰性队列适用场景:在非常长的队列(百万条消息),生产者的速度超过消费者,消费者处理慢,使用惰性队列;它把消息放在队列中,并不是马上进行持久化操作,是在有空闲时,当队列达到百分之多少时,再进行数据持久化操作。

// x-queue-mode 参数,可在插件安装配置
@Queue(value = 队列名字, durable = "true", autoDelete = "false", arguments = {
	@Argument(name = "x-queue-mode", value = "lazy")
})

队列消息优先级

创建队列,如果这个值是0,代表优先级无效,设置的值优先级不能超过该值,优先级越高占用内存资源越多。
在这里插入图片描述

生产者配置

@Resource
private RabbitTemplate rabbitTemplate;

// 生产者发送消息 1  - 优先级是1
rabbitTemplate.convertAndSend(EXCHANGE_PRIORITY, ROUTING_KEY_PRIORITY, "生产者发送消息 - 演示优先级:1", message -> {
    message.getMessageProperties().setPriority(1);
    return message;
});
// 生产者发送消息 2  - 优先级是2
rabbitTemplate.convertAndSend(EXCHANGE_PRIORITY, ROUTING_KEY_PRIORITY, "生产者发送消息 - 演示优先级:2", message -> {
    message.getMessageProperties().setPriority(2);
    return message;
});
// 生产者发送消息 3  - 优先级是3
rabbitTemplate.convertAndSend(EXCHANGE_PRIORITY, ROUTING_KEY_PRIORITY, "生产者发送消息 - 演示优先级:3", message -> {
    message.getMessageProperties().setPriority(3);
    return message;
});
// 生产者发送消息1、消息2、消息3的顺序(先进先出)
// 但消费者,消费优先消费:消息3、消息2、消息1 (改变了消费的顺序)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【PyQt5】一文向您详细介绍 setSpacing() 的作用

【PyQt5】一文向您详细介绍 setSpacing() 的作用 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&am…

南昌服务器托管让数据存储更安全

南昌&#xff0c;作为长江中游地区的重要中心城市&#xff0c;近年来经济发展迅速&#xff0c;产业结构不断优化。随着大数据、云计算、人工智能等新一代信息技术的快速发展&#xff0c;南昌的信息化建设步伐不断加快&#xff0c;为企业提供了良好的发展环境。在这样的背景下&a…

LabVIEW技术交流-控件的禁用属性与Mouse Up事件的一个坑

问题来源 我们平时对控件Mouse Up事件触发使用场景不多&#xff0c;可能在按钮控件上会偶尔用到。在一些场景中&#xff0c;我们用按钮的Mouse Up触发事件&#xff0c;但是又希望在某些限制条件下&#xff0c;按钮会被禁用而不能触发事件。 可是当我们禁用按钮时&#xff0c;它…

P2实验室装修标准都有哪些

P2实验室&#xff08;也称为生物安全二级实验室&#xff0c;BSL-2实验室&#xff09;的装修标准需要满足一系列的设计和施工要求&#xff0c;以确保实验室的安全性和功能性。因此&#xff0c;P2实验室装修标准不仅要满足一般实验室的要求&#xff0c;还需符合生物安全的特殊规定…

穿越千年的智慧之光——唐宋时期的节能“黑科技”省油灯

唐宋时期&#xff0c;中国古代科技达到了一个高峰&#xff0c;许多创新发明不仅在当时引领潮流&#xff0c;甚至在今天看来也充满了智慧的光辉。其中&#xff0c;一项名为“省油灯”的发明&#xff0c;便是当时节能减排的杰出代表&#xff0c;连著名诗人陆游都为之倾倒&#xf…

123.网络游戏逆向分析与漏洞攻防-邮件系统数据分析-收邮件功能的完善与优化

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

最强开源模型来了!一文详解 Stable Diffusion 3 Medium 特点及用法

前言 最强开源模型来了&#xff01;一文详解 Stable Diffusion 3 Medium 特点及用法&#xff08;附模型资源包&#xff09; 大家好&#xff0c;我是AI绘画小33~ 备受期待的 Stable Diffusion 3&#xff08;以下简称 “SD3”&#xff09;终于向公众开放了&#xff0c;作为 S…

大厂薪资福利篇第四弹:字节跳动

欢迎来到绝命Coding&#xff01; 今天继续更新大家最关心的 大厂薪资福利系列&#xff01; 往期分享&#xff1a; 福利开水喝不完&#xff1f;大厂薪资福利篇&#xff01;美团 职场文化发源地&#xff1f;大厂薪资福利篇&#xff01;阿里巴巴 给这么多&#xff01;还能带宠物上…

用英文介绍纽约:NEW YORK, USA‘s MEGACITY

NEW YORK, USA’s MEGACITY | America’s Largest City Link: https://www.youtube.com/watch?vdzjQ-akB3BI&listPLmSQiOQJmbZ7TU39cyx7gizM9i8nOuZXy&index24 The story of New York City, America’s megalopolis. Summary Paragraph 1: The Historical Developm…

站在巨人的肩膀上 C语言理解和简单练习(包含指针前的简单内容)

1.格式化的输入/输出 1.1printf函数 printf函数你需要了解的就是转换说明&#xff0c;转换说明的作用是将内存中的二进制转换成你所需要的格式入%d就是将内存中存储的变量的二进制转化为十进制并打印出来&#xff0c;同时我们可以在%X的转换说明对精度和最小字段宽度的指定&a…

第 133 场 LeetCode 双周赛题解

A 使所有元素都可以被 3 整除的最少操作数 遍历 n u m s nums nums &#xff0c;每有一个不被 3 3 3 整除的数&#xff0c;则操作数加 1 1 1 class Solution {public:int minimumOperations(vector<int>& nums) {int res 0;for (auto x : nums)if (x % 3 ! 0)res…

基于JSP的在线教育资源管理系统

开头语&#xff1a; 你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果你对在线教育资源管理系统感兴趣或者有相关需求&#xff0c;欢迎在文末找到我的联系方式。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 工具&#xff1a;IDE、N…

excel表格加密:电脑文件加密的5个方法介绍【新手篇】

为了防止数据泄露&#xff0c;编辑好表格文件后一般都会加上密码。敏感数据的泄露会导致严重的商业损失和声誉损害。Excel表格加密方法有很多&#xff0c;包括金舟文件夹加密大师、金舟ZIP解压缩、工作簿密码设置等方法。 下面分享5个excel表格加密方法&#xff0c;希望能够帮到…

RuoYi-Vue教程

若依搭建 若依版本 官方 若依官方针对不同开发需求提供了多个版本的框架&#xff0c;每个版本都有其独特的特点和适用场景&#xff1a; 前后端混合版本&#xff1a;RuoYi结合了SpringBoot和Bootstrap的前端开发框架&#xff0c;适合快速构建传统的Web应用程序&#xff0c;其…

36.基于多目标螳螂优化算法的微电网优化matlab

微♥关注“电击小子程高兴的MATLAB小屋”获取资源 基于螳螂优化算法的多目标优化算法 求解微电网多目标优化调度 比较不同目标函数寻优对调度结果的影响 第1种.将两个目标函数值归一化相加&#xff0c;取相加后最小的目标值的粒子&#xff0c;即寻找折衷解并画图 第2种寻找…

代码随想录-Day39

62. 不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&…

服务器硬件及RAID配置

目录 一、RAID磁盘阵列 1.概念 2.RAID 0 3.RAID 1 4.RAID 5 5.RAID 6 6.RAID 10 二、阵列卡 1.简介 2.缓存 三、创建 1.创建RAID 0 2.创建RAID 1 3.创建RAID 5 4.创建RAID 10 四、模拟故障 一、RAID磁盘阵列 1.概念 &#xff08;1&#xff09;是Redundant Array …

【Java毕业设计】基于JavaWeb的房屋出租系统

本科毕业设计论文 题目&#xff1a;房屋交易平台设计与实现 系 别&#xff1a; XX系&#xff08;全称&#xff09; 专 业&#xff1a; 软件工程 班 级&#xff1a; 软件工程15201 学生姓名&#xff1a; 学生学号&#xff1a; 指导教师&#xff1a; 导师1 导师2 文章目录 摘…

【Linux】性能分析器 perf 详解(一)

1、简介 perf 是由 Linux 官方提供的系统性能分析工具 。它包含两部分: perf_events ,Linux 内核中的一个子系统perf 命令,用户空间的应用程序内核子系统 perf_events 提供了性能计数器(hardware performance counters)和性能事件的支持,它以事件驱动型的方式工作,通过…

数据独立性-信息、数据、数据结构、数据独立性

一、引言 同人工管理数据和文件系统管理数据相比&#xff0c;数据库管理数据最主要的优点是数据独立性高。数据独立性是数据库领域中的一个常用术语和重要概念&#xff0c;包括数据的物理独立性和逻辑独立性 二、数据与数据结构 1、信息 在数据管理领域&#xff0c;数据与信…