RabbitMQ个人理解与基本使用

ops/2024/12/20 0:32:31/

目录

一. 作用:

二. RabbitMQ的5中队列模式:

1. 简单模式

2. Work模式

3. 发布/订阅模式

4. 路由模式

5. 主题模式

三. 消息持久化:

消息过期时间

ACK应答 

四. 同步接收和异步接收:

应用场景

五. 基本使用 :

引入依赖库:

配置文件RabbitMQConfig: 

创建消息任务类: 

解析:


一. 作用:

        RabbitMQ主要用于消息队列的实现。

二. RabbitMQ的5中队列模式:

1. 简单模式

一个生产者(发送方)对应一个消费者(接收方)

2. Work模式

一个生产者对应多个消费者,但是只能有一个消费者获得消息(排他)

3. 发布/订阅模式

一个消费者将消息首先发送到fanout交换器,交换器绑定到多个队列,然后与之对应的所有消费者都能接收到消息(不排他)

4. 路由模式

生产者将消息发送到direct交换器,交换器按照关键字(Key),把消息路由到某个队列

5. 主题模式

生产者将消息发送到Topic交换器,交换器按照复杂的规则,把消息路由到某个队列

三. 消息持久化:

        消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证消息可靠性的呢?答案就是消息持久化。持久化可以防止在异常情况下丢失数据。除了消息持久化之外,甚至交换器和队列都能持久化。也就是说rabbitmq的消息会被存储在磁盘上,只有当消费收到消息,rabbitmq确认消费者收到消息(Acknowledgments--简称ACK)后才会将消息从队列中删除。  

  • 消息过期时间

        如果消费者一直不接收消息,消息会一直保存在消息队列当中,短期内可能不会有什么影响,但是如果经过长时间的积累后,消息会变得很多很多 ,浪费大量的资源,内存。

        为了应对这种情况,就可以对rabbitmq设置消息的过期时间,在规定时间内消息没有被接收,就会删除掉该消息。

  • ACK应答 

        消费者接收到消息后,为了让RabbitMQ 知道,就需要返回一个ACK应答,告诉RabbitMQ消费者已经收到了消息,如果收到消息后我们需要删除该消息,只需要在ACK应答中加上deliveryTag标志位。

四. 同步接收和异步接收:

        同步接收:指消费者调用方法时,会阻塞来等待消息,直到消息被成功消费或者队列为空。(没有消息等待消息再接着处理)。

        异步接收: 指消费者不会在接收消息时阻塞,而是通过回调函数处理消息。消费者在等待消息的同时不会停下,可以处理其他任务。(当有消息时才来处理消息)。

  • 应用场景

        同步接收 :当消息的处理顺序对业务逻辑非常重要,就使用同步接收,消费者一次只处理一个消息,确保了每条消息的处理顺序。

        异步接收:当处理消息的时间比较长,或者系统的并发量大时,采用异步接收会更好。

RabbitMQ还有一个杀手锏——同时使用异步收发和同步收发。

五. 基本使用 :

引入依赖库:

<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.9.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency> 

配置文件RabbitMQConfig: 

java">import com.rabbitmq.client.ConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {@Value("${rabbitmq.factoryHost}")private String host;@Beanpublic ConnectionFactory connectionFactory() {ConnectionFactory factory = new ConnectionFactory();factory.setHost(host);factory.setPort(5672);return factory;}
}

 host配置,我将rabbitMQ放在虚拟机上的,所有ip是虚拟机的地址:

创建消息任务类: 

java">@Slf4j
@Component
public class MessageTask {@Autowiredprivate ConnectionFactory factory;@Autowiredprivate MessageService messageService;/** 同步发送消息* */public void send(String topic, MessageEntity entity) {//向MongoDB保存消息数据,返回消息IDString id = messageService.insertMessage(entity);//向RabbitMQ发送消息try(Connection connection = factory.newConnection();Channel channel = connection.createChannel()){//连接到某个topicchannel.queueDeclare(topic, true, false, false, null);HashMap header = new HashMap();header.put("messageId",id);//创建AMQP协议参与对象,添加附加属性AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().headers(header).build();channel.basicPublish("",topic,properties,entity.getMsg().getBytes());log.debug("消息发送成功");} catch (Exception e){log.error(e.getMessage());throw new EmosException("向MQ发送消息失败");}}/** 异步发送消息* */@Async("AsyncTaskExecutor")public void sendAsync(String topic, MessageEntity entity) {send(topic, entity);}/** 同步接收消息* */public int receive(String topic) {int i = 0;try (//接收消息数据Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {// 从队列中获取消息,不自动确认channel.queueDeclare(topic, true, false, false, null);//Topic中有多少条数据未知,所以使用死循环接收数据,直到接收不到消息,退出死循环while (true) {//创建响应接收数据,禁止自动发送Ack应答GetResponse response = channel.basicGet(topic, false);if (response != null) {AMQP.BasicProperties properties = response.getProps();Map<String, Object> header = properties.getHeaders(); //获取附加属性对象String messageId = header.get("messageId").toString();byte[] body = response.getBody();//获取消息正文String message = new String(body);log.debug("从RabbitMQ接收的消息:" + message);MessageRefEntity entity = new MessageRefEntity();entity.setMessageId(messageId);entity.setReceiverId(Integer.parseInt(topic));entity.setReadFlag(false);entity.setLastFlag(true);messageService.insertRef(entity); //把消息存储在MongoDB中//数据保存到MongoDB后,才发送Ack应答,让Topic删除这条消息long deliveryTag = response.getEnvelope().getDeliveryTag();channel.basicAck(deliveryTag, false);i++;} else {break; //接收不到消息,则退出死循环}}} catch (Exception e) {log.error("执行异常", e);}return i;}/** 异步接收消息* */@Asyncpublic int receiveAsync(String topic) {return receive(topic);}/** 同步删除消息* */public void deleteQueue(String topic) {try(//接收消息数据Connection connection = factory.newConnection();Channel channel = connection.createChannel()){channel.queueDelete(topic);log.debug("成功删除消息队列:"+topic);} catch (Exception e){log.error("删除消息队列失败:",e);throw new EmosException("删除消息队列失败");}}/** 异步删除消息* */@Asyncpublic void deleteAsync(String topic) {deleteQueue(topic);}
}

解析:

java">channel.queueDeclare(String queueName, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments);
  • queueName:队列的名称,用于标识消息的存储位置。
  • durable:

        true,表示队列是持久化的。

        false,表示队列是非持久化的。

  • exclusive:

        true:队列仅供当前连接使用,连接断开时队列会自动删除。

        false:队列可供多个连接共享。

  • autoDelete:
    true:当队列不再被任何消费者订阅时,队列会自动删除。
    false:队列即使没有消费者订阅也会一直存在,直到手动删除。

  • arguments:额外的参数,null表示没有额外参数

Map<String, Object> arguments = new HashMap<>();
arguments.put("x-message-ttl", 60000); // 设置队列中消息的过期时间为 60 秒(60000 毫秒)

channel.queueDeclare("myQueue", true, false, false, arguments);


http://www.ppmy.cn/ops/143328.html

相关文章

12.13 深度学习-卷积的注意力机制通道注意力SKNet

# **Selective Kernel Networks** 可选择的 卷积核尺寸 # SK是对SE的改进版&#xff0c;可以动态调整感受野大小 import torch import os import torch.nn as nn from torchvision.models import resnet18,ResNet18_Weights from torchvision.models.resnet import _res…

在 Docker 容器内运行 MySQL 并执行 SQL 脚本文件

在 Docker 容器内运行 MySQL 并执行 SQL 脚本文件&#xff08;如 cube_admin.sql&#xff09;&#xff0c;可以通过几种方式实现。以下是一种常见的方法&#xff0c;假设已经将 SQL 脚本文件 cube_admin.sql 放置在容器可以访问的位置&#xff08;例如&#xff0c;通过 Docker …

SSM 构建基石,Vue 添彩助力:新锐台球厅管理系统的设计与实现

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常适…

leetcode236.二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它自己的…

Springboot家政服务管理系统

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…

vue3中provide 、inject的比较

引言 在 Vue 3 中,provide 和 inject 是用于在组件之间共享数据的 API。这种机制允许父组件向其子组件提供数据,而不需要通过 props 一层层传递。以下是对 provide 和 inject 的详细解释以及示例代码。 provide 和 inject 的工作原理 provide:在父组件中使用,允许…

Rust中自定义Debug调试输出

在 Rust 中&#xff0c;通过为类型实现 fmt::Debug&#xff0c;可以自定义该类型的调试输出。fmt::Debug 是标准库中的一个格式化 trait&#xff0c;用于实现 {:?} 格式的打印。这个 trait 通常通过自动派生&#xff08;#[derive(Debug)]&#xff09;来实现&#xff0c;但你也…

Ilya Sutskever发表了对AI未来发展的颠覆性看法

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…