RabbitMQ入门详解

embedded/2024/10/18 10:25:50/

前言

本篇文章将详细介绍rabbitmq的基本概念知识,以及rabbitmq各个工作模式在springboot中如何使用。

文章目录

介绍

简介

RabbitMQ 核心

生产者与消费者

Exchange

Queue

工作模式

简单模式

工作队列模式

发布订阅模式

路由模式

主题模式

SpringBoot中使用RabbitMQ

简单模式

基础配置

生产者

消费者

工作队列模式

发布/订阅模式(广播模式)

路由模式

主题模式


介绍

简介

RabbitMQ 是采用 Erlang 语言实现 AMQP(Advanced Message Queuing Protocol,高级消息队列协议)的消息中间件,它最初起源于金融系统,用于在分布式系统中存储转发消息。

RabbitMQ 发展到今天,被越来越多的人认可,这和它在易用性、扩展性、可靠性和高可用性等方面的卓著表现是分不开的。RabbitMQ 的具体特点可以概括为以下几点:

  • 可靠性: RabbitMQ使用一些机制来保证消息的可靠性,如持久化、传输确认及发布确认等。

  • 灵活的路由: 在消息进入队列之前,通过交换器来路由消息。对于典型的路由功能,RabbitMQ 己经提供了一些内置的交换器来实现。针对更复杂的路由功能,可以将多个交换器绑定在一起,也可以通过插件机制来实现自己的交换器。这个后面会在我们将 RabbitMQ 核心概念的时候详细介绍到。

  • 扩展性: 多个RabbitMQ节点可以组成一个集群,也可以根据实际业务情况动态地扩展集群中节点。

  • 高可用性: 队列可以在集群中的机器上设置镜像,使得在部分节点出现问题的情况下队列仍然可用。

  • 支持多种协议: RabbitMQ 除了原生支持 AMQP 协议,还支持 STOMP、MQTT 等多种消息中间件协议。

  • 多语言客户端: RabbitMQ几乎支持所有常用语言,比如 Java、Python、Ruby、PHP、C#、JavaScript等。

  • 易用的管理界面: RabbitMQ提供了一个易用的用户界面,使得用户可以监控和管理消息、集群中的节点等。在安装 RabbitMQ 的时候会介绍到,安装好 RabbitMQ 就自带管理界面。

  • 插件机制: RabbitMQ 提供了许多插件,以实现从多方面进行扩展,当然也可以编写自己的插件。感觉这个有点类似 Dubbo 的 SPI机制。

RabbitMQ 核心

生产者与消费者

RabbitMQ 整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。可以把消息传递的过程想象成:当你将一个包裹送到邮局,邮局会暂存并最终将邮件通过邮递员送到收件人的手上,RabbitMQ就好比由邮局、邮箱和邮递员组成的一个系统。

  • Producer(生产者) :生产消息的一方(邮件投递者)

  • Consumer(消费者) :消费消息的一方(邮件收件人)

消息一般由 2 部分组成:消息头(或者说是标签 Label)和 消息体。消息体也可以称为 payLoad ,消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。生产者把消息交由 RabbitMQ 后,RabbitMQ 会根据消息头把消息发送给感兴趣的 Consumer(消费者)。

Exchange

在 RabbitMQ 中,消息并不是直接被投递到Queue中的,中间还必须经过 Exchange(交换机) 这一层,Exchange 会把我们的消息分配到对应的Queue中。

Exchange用来接收生产者发送的消息并将这些消息路由给服务器中的队列中,如果路由不到,或许会返回给 Producer(生产者) ,或许会被直接丢弃掉 。这里可以将RabbitMQ中的交换器看作一个简单的实体。

RabbitMQ 的 Exchange(交换器) 有4种类型,不同的类型对应着不同的路由策略:direct(默认)fanout, topic, 和 headers,不同类型的Exchange转发消息的策略有所区别。

Queue

Queue(消息队列) 用来保存消息直到发送给消费者。RabbitMQ 中消息只能存储在队列中 ,它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。

多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊(Round-Robin,即轮询)给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理,这样避免的消息被重复消费。

工作模式

简单模式

RabbitMQ简单模式,也称为基本模式(Basic Model),是RabbitMQ的最简单的消息传递模式,仅涉及到一个生产者和一个消费者。

在这个模式中,当我们启动一个程序作为生产者并向RabbitMQ发出消息时,我们希望它直接进入队列中,然后消费者会从队列中获取这个消息并进行处理。

简单模式在RabbitMQ中是一个单队列单生产者单消费者的模式,主要适用于单纯的任务处理,消息的生产者和消费者的削峰填谷能力非常高。

工作队列模式

RabbitMQ工作队列模式,也称为Task Queues或Background Tasks,是一种常见的应用场景,它用于处理大量的任务,将任务进行排队,然后分发给多个消费者进行处理。这种模式适用于需要异步处理耗时的、密集型任务并且要求可靠性的情况。

RabbitMQ工作队列模式的基本原理是,将需要处理的任务投递到RabbitMQ中,生成任务队列(Task Queues),多个消费者通过拉取任务队列中的任务进行处理。

在RabbitMQ的工作队列模式中,队列中的每个消息都会分配给一个消费者进行处理。消费者可以是不同的进程、线程或服务,从而实现可扩展性和并行性。

在一个生产者-多个消费者的场景下,生产者只需要将消息发送到一个消息队列中,消费者会自动从队列中获取消息进行处理。如果存在多个消费者,队列中的消息将会被分摊给多个消费者进行处理,即实现了任务并行处理的功能。而且如果一个消费者挂掉,该消费者所占用的任务在一定的时间内不会被重新分配,即实现了任务可靠性处理的功能。

一般情况下,RabbitMQ的工作队列模式可以应用于以下场景:

  • 任务比较繁重,处理较慢
  • 任务多且耗时,无法同步处理
  • 需要执行一些必须的后台任务,如发送邮件、生成报表等

发布订阅模式

RabbitMQ发布/订阅模式,也叫做“广播(Broadcast)模式”,是RabbitMQ的一种高级消息传递模式,主要用于广播消息。

在发布/订阅模式中,消息发送到Exchange(交换机)上,并携带着一个Routing Key(路由键),Exchange将收到的消息转发到绑定在它上面的所有队列。每个绑定键(Binding Key)都与一个队列相关联,而队列和消息的接收者实现了完全解耦,接收者只需要订阅(subscribe)与该队列相关联的绑定键即可。

我们将它作为“广播”模式,因为可以将一条消息同时发送到多个消费者。例如,我们可以让多个消费者接收网站上发布的新闻消息。

发布/订阅模式在RabbitMQ中的架构非常简单,主要可以描述为以下四个步骤:

  • 生产者将消息发送到exchange中,并指定了Routing Key。
  • Exchange将消息分发到所有绑定它的队列上。
  • 消费者从队列中接收消息,并进行处理。
  • 消费者对队列进行确认操作,告诉RabbitMQ该消息已经被接收并处理。

路由模式

RabbitMQ路由模式是一种高级消息传递模式,它可以通过选择路由键(Routing Key)将消息推送到绑定键(Binding Key)与之匹配的队列中,以满足不同的消费者需要。

路由模式主要用于单一应用程序内的消息传递,生产者将消息发送到指定的Exchange(交换机)中,并且Exchange会根据Routing Key将消息放到绑定到Exchange上的队列中。而不同的消费者使用不同的Binding Key来决定与哪个队列建立联系并接收消息。

在RabbitMQ中,路由模式有以下几个步骤:

  • 生产者将消息发送到Exchange中,并指定了Routing Key。
  • Exchange将消息根据Routing Key发送到绑定到Exchange中的队列。
  • 消费者从队列中接收消息,并进行处理。
  • 消费者对队列进行确认操作,告诉RabbitMQ该消息已经被接收并处理。

主题模式

RabbitMQ主题模式(Topic Model)是一种高级消息传递模式,它使你可以订阅一个特定的主题(Topic)并接收所有与该主题相关的消息。主题模式是在发布/订阅模式基础上进一步增强了消息传递的粒度。

在主题模式中,Exchange不仅可以使用Routing Key来将消息传递到队列中,还可以使用一个模式字符串来匹配Routing Key,这个模式字符串被称为主题(Topic)。消费者可以通过订阅不同的主题来接收不同的消息。

一个主题可以包含一个或多个单词(Word),单词之间使用"."(点号)来分割。通配符符号“#”表示跟单词数不限,而“”则表示只匹配一个单词。

主题模式在RabbitMQ中的架构非常简单,主要可以描述为以下四个步骤:

  • 生产者将消息发送到Exchange中,并指定了Routing Key。
  • Exchange将消息根据匹配的主题字符串发送到绑定到Exchange中的队列。
  • 消费者从队列中接收消息,并进行处理。
  • 消费者对队列进行确认操作,告诉RabbitMQ该消息已经被接收并处理。

SpringBoot中使用RabbitMQ

在使用之前先要确保在电脑中已经安装了rabbitmq,并启动服务,启动成功后是可以在本地15672端口中访问到网页的。如图:

简单模式

基础配置

首先创建两个SpringBoot项目,一个作为消费者,一个作为生产者,并导入依赖项。

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

 在两个项目的yaml文件中写入rabbitmq的配置信息

spring:rabbitmq:host: localhost # 主机名port: 5672 # 端口virtual-host: / # 虚拟主机username: guest # 用户名password: guest # 密码

rabbitmq中创建一个队列叫做queue1

生产者

在生产者中编写测试类,发送消息

java">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
class RabbitPublisherApplicationTests {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void SimpleQueue(){//队列名字String name = "queue1";//具体的消息String message = "你好!!!rabbit";//发送消息rabbitTemplate.convertAndSend(name,message);}
}

执行测试类后在rabbitmq的相应队列中就会有消息了。

消费者

随后编写消费者来消费消息。

创建一个监听类,来监听具体的队列

java">@Component
public class SpringRabbitListener {/*** 从队列queue1中取消息* @param msg*/@RabbitListener(queues = "queue1")public void listenSimpleQueueMessage(String msg) {System.out.println("spring 消费者接收到消息:" + msg);}
}

随后启动消费者项目,就可以从队列中成功获取到消息了。

工作队列模式

编写方法发送20条消息

java">    @Testpublic void WorkQueue(){String name = "work.queue";for(int i=0;i<20;i++){String message = "第"+i+"消息";rabbitTemplate.convertAndSend(name,message);}}

用两个消费者来接收

java">    @RabbitListener(queues = "work.queue")public void listenWorkQueueMessage1(String msg) {System.out.println("第一位消费者接收到消息:" + msg);}@RabbitListener(queues = "work.queue")public void listenWorkQueueMessage2(String msg) {System.out.println("第二位消费者接收到消息:" + msg);}

先启动消费者再发送消息:

此时可以发现两个消费者将消息均匀分配,每位各接收10条消息,这里是因为mq有预分配,会先预取,每个消费者和队列中有一个通道,存放预取的消息,所以会平均分消息,然后各自独立消费。

但是假如我们的消费者消费能力不一样呢,rabbitmq也会将其平均分配,这样的机制显然是不合理的,因此面对这种情况时,可以通过控制预取数量来改变这种情况,我们可以在yml文件中编写配置。这样就实现了取一个消费一个,不会先预取很多个,如果消费能力强取得就快,消费能力弱,取得就慢。

java">spring:rabbitmq:host: localhost # 主机名port: 5672 # 端口virtual-host: / # 虚拟主机username: guest # 用户名password: guest # 密码listener:simple:prefetch: 1

发布/订阅模式(广播模式)

广播模式使用fanout交换机

首先编写一个配置类,配置交换机和队列

java">@Configuration
public class FanoutConfig {//声明交换机,设置名称@Beanpublic FanoutExchange fanoutExchange() {return new FanoutExchange("exchange1");}//队列1@Beanpublic Queue fanoutQueue1() {return new Queue("fanout1",true);}//绑定队列1和交换机@Beanpublic Binding binding1() {return BindingBuilder.bind(fanoutQueue1()).to(fanoutExchange());}//队列2@Beanpublic Queue fanoutQueue2() {return new Queue("fanout2",true);}//绑定交换机和队列2@Beanpublic Binding bindingQueue2() {return BindingBuilder.bind(fanoutQueue2()).to(fanoutExchange());}
}

发送消息

java">    @Testpublic void fanout(){String name = "exchange1";String meg = "这里时fanout";rabbitTemplate.convertAndSend(name,"",meg);}

接收消息

java">    @RabbitListener(queues = "fanout1")public void listenWorkQueueMessage1(String msg) {System.out.println("第一位消费者接收到消息:" + msg);}@RabbitListener(queues = "fanout2")public void listenWorkQueueMessage2(String msg) {System.out.println("第二位消费者接收到消息:" + msg);}

结果我们可以看到两个消费者都接收到了消息。

路由模式

路由模式使用direct交换机,除了使用配置类的方式进行队列和交换机的绑定,还可以在消费者中使用注解的方式,例如

java">    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue1"),exchange = @Exchange(name="direct",type = ExchangeTypes.DIRECT),key = {"one","two"}))public void directListener1(String msg){System.out.println("第一位消费者接收到来自direct.queue1的消息:"+ msg);}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue2"),exchange = @Exchange(name="direct",type = ExchangeTypes.DIRECT),key = {"three"}))public void directListener2(String msg){System.out.println("第二位消费者接收到来自direct.queue2的消息:"+ msg);}

发送消息

java">    @Testpublic void directTest(){// 交换机名称String exchangeName = "direct";// 消息String message = "第 one 消息";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "one", message);// 消息String message2 = "第 two 消息";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "two", message2);// 消息String message3 = "第 three 消息";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "three", message3);}

最后可以看到,根据key路由接收到了消息。

主题模式

主题模式和路由模式类似,使用topic交换机,只是可以在key中使用通配符,

主题模式中RoutingKey一般由一个或多个单词组成,用“.”分割。

通配符规则

# 匹配一个或多个词

* 匹配一个词

修改消费者配置

java">    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue1"),exchange = @Exchange(name="topic",type = ExchangeTypes.TOPIC),key = {"a.*"}))public void topicListener1(String msg){System.out.println("第一位消费者接收到来自topic.queue1的消息:"+ msg);}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue2"),exchange = @Exchange(name="topic",type = ExchangeTypes.TOPIC),key = {"a.#"}))public void topocListener2(String msg){System.out.println("第二位消费者接收到来自topic.queue2的消息:"+ msg);}

发送消息

java">    @Testpublic void topicTest(){// 交换机名称String exchangeName = "topic";String message = "消息:a.b";rabbitTemplate.convertAndSend(exchangeName, "a.b", message);String message2 = "消息:a.b.c";rabbitTemplate.convertAndSend(exchangeName, "a.b.c", message2);String message3 = "消息:a.b.c.d";rabbitTemplate.convertAndSend(exchangeName, "a.b.c.d", message3);}

最后结果可以看到,第二个消费者可以拿到所有消息,第一个消费者只能拿到a.b的消息


http://www.ppmy.cn/embedded/85635.html

相关文章

.net core 外观者设计模式 实现,多种支付选择

1&#xff0c;接口 /// <summary>/// Web页面支付/// </summary>public interface IWebPagePay{public WebPagePayResult CreatePay(string productName, string orderSn, string totalPrice);}2&#xff0c;实现接口 实现阿里支付 public class AliPagePay : IWe…

【C++】C++中的find方法介绍

目录 一.find方法基本用法 1.查找字符 2.查找子字符串 3.查找子字符串&#xff08;从指定位置开始&#xff09; 4.查找字符范围 5.查找不包含特定字符的范围 二.使用string::npos返回无效位置 三.总结 在C中&#xff0c; std::string 类的 find 成员函数用于查找子字…

JavaDS —— 排序

排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&a…

iOS object-C 解答算法:找到所有数组中消失的数字(leetCode-448)

找到所有数组中消失的数字(leetCode-448) 题目如下图:(也可以到leetCode上看完整题目,题号448) 光看题看可能有点难以理解,我们结合示例1来理解一下这道题. 有8个整数的数组 nums [4,3,2,7,8,2,3,1], 求在闭区间[1,8]范围内(即1,2,3,4,5,6,7,8)的数字,哪几个没有出现在数组 …

[Day 34] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

機器學習模型的訓練與評估 機器學習模型的訓練與評估是整個機器學習過程中的核心部分。這篇文章將詳細探討如何訓練和評估機器學習模型&#xff0c;並提供具體的代碼示例和詳細解釋&#xff0c;幫助讀者更好地理解和掌握這些技術。 一、機器學習模型的訓練 模型訓練是機器學…

利用换元法计算积分的常见题型(考研高数复习)

考研中常见的几种换元法积分计算题 (1)被积式仅包含一个根式&#xff1a;根号下为有 a a a 和 x x x 的平方和/平方差 此种类型的积分题型&#xff0c;可以通过构造单个锐角大小为 t t t 的直角三角形&#xff0c;利用勾股定理和三角函数进行代换。 平方和的情况 形如 ∫…

了解网络是如何运作

“Web 的工作原理”提供了一个简化的视图,用于了解在计算机或手机上的 Web 浏览器中查看网页时发生的情况。 这个理论对于短期内编写 Web 代码来说并不是必需的,但不久之后,你就会真正开始从理解后台发生的事情中受益。 客户端和服务器 连接到 Internet 的计算机称为客户端和…

网站用HTTP访问的危害以及如何升级HTTPS访问

在互联网世界中&#xff0c;数据传输的安全性是至关重要的。我们每天都在网络上进行各种操作&#xff0c;从浏览网页、购物到银行转账&#xff0c;每一项活动都涉及敏感信息的传递。然而&#xff0c;在这个过程中&#xff0c;我们的数据可能面临被窃取、篡改或滥用的风险。这正…