消息队列RabbitMQ

本文详细介绍了RabbitMQ的原理、安装、运行机制、图形界面使用、整合及消息确认机制,包括Direct、Fanout、Topic交换机类型,以及消息的发送与接收。RabbitMQ是一个基于AMQP协议的开源消息队列系统,通过解耦生产者和消费者来实现服务间的通信。文章展示了如何在Spring Boot中使用RabbitMQ,并探讨了消息的可靠抵达策略。
摘要由CSDN通过智能技术生成

一、RabbitMQ

1.1现实问题

目前我们已经完成了商品和搜索系统的开发。我们思考一下,是否存在问题?

  • 商品的原始数据保存在数据库中,增删改查都在数据库中完成。
  • 搜索服务数据来源是索引库,如果数据库商品发生变化,索引库数据不能及时更新。

如果我们在后台修改了商品的价格,搜索页面依然是旧的价格,这样显然不对。该如何解决?

这里有两种解决方案:

  • 方案1:每当后台对商品做增删改操作,同时要修改索引库数据
  • 方案2:搜索服务对外提供操作接口,后台在商品增删改后,调用接口

以上两种方式都有同一个严重问题:就是代码耦合,后台服务中需要嵌入搜索和商品页面服务,违背了微服务的独立原则。

所以,我们会通过另外一种方式来解决这个问题:消息队列

image-20220530083747069

image-20220530083755592

1.2消息队列(MQ)

1.2.1什么是消息队列

消息队列,即MQ,Message Queue。

消息队列是典型的:生产者、消费者模型。生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦。

结合前面所说的问题:

  • 商品服务对商品增删改以后,无需去操作索引库,只是发送一条消息,也不关心消息被谁接收。
  • 搜索服务服务接收消息,去处理索引库。

如果以后有其它系统也依赖商品服务的数据,同样监听消息即可,商品服务无需任何代码修改。

1.2.2AMQP和JMS

MQ是消息通信的模型,并不是具体实现。现在实现MQ的有两种主流方式:AMQP、JMS。

两者间的区别和联系:

  • JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式
  • JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。
  • JMS规定了两种消息模型;而AMQP的消息模型更加丰富
1.2.3常见的MQ产品
  • ActiveMQ:基于JMS
  • RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好
  • RocketMQ:基于JMS,阿里巴巴产品,目前交由Apache基金会
  • Kafka:分布式消息系统,高吞吐量
1.2.4 RabbitMQ

RabbitMQ是基于AMQP的一款消息管理系统

官网: http://www.rabbitmq.com/

官方教程:http://www.rabbitmq.com/getstarted.html
image-20220530083911551

image-20220530084012071

image-20220530094916629

消息中间件的两大规范:JMS,AMQP

RabbitMQ就是根据AMQP实现,也兼容JMS

提供的五种消息模型,第一种就是对队列的实现,后四种是我们发布订阅的变形实现

也就是遵循了两种实现,一个订阅的模式(发布订阅主体模式),还有一个队列模式点对点

假设我们有一个对象想要传出去,但它传输只支持流,我们把对象序列化成json,json就是一个字符串,把字符串以流的形式(byte)传输出去

image-20220530100114208

spring boot无论整合那个消息中间件都非常简单,因为spring boot已经原生支持JMS,RabbitMQ

二、RabbitMQ概念

RabbitMQ简介:

RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue Protocol)的开源实现。

核心概念

  • Message:消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则有一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

  • Publisher:消息生产者,也是一个向交换器发布消息的客户端应用程序。

  • Exchange:交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。Exchange有四种类型:direct(默认),fanout,topic,和headers,不同类型的Echange转发消息的策略有所区别

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

  • Binding:绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。Exchange和Queue的绑定可以是多对多的绑定。

  • Connection:网络连接,比如一个TCP连接

  • Channel:信道,多路复用连接中的一条独立的双向绑定数据流通道。信道是建立在真实的TCP连接内的虚拟连接,AMQP命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁TCP都是非常昂贵的开销,所以引入信道的概念,以复用一条TCP连接。

  • Consumer:消费的消费者,表示一个从消息队列中取得消息的客户端应用程序

  • Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个vhost本质上就是一个mini版的RabbitMQ服务器,拥有自己的队列、交换器、绑定和权限机制。vhost是AMQP概念的基础,必须是在连接时指定,RabbitMQ默认的是vhost是/。

  • Broker:表示消息队列服务器实体

    image-20220530110720131

    原理如下:

image-20220530111420617

三、Docker安装RabbitMQ

image-20220530112514861

3.1安装

下载镜像:docker pull rabbitmq:management

创建实例并启动:

docker run -d --name rabbitmq --publish 5671:5671 \
--publish 5672:5672 --publish 4369:4369 --publish 25672:25672 --publish 15671:15671 --publish 15672:15672 \
rabbitmq:management
加上这个命令,以后虚拟机docker一启动,rabbitmq就启动
docker update rabbitmq --restart=always

注意:

4369 – erlang发现口
5672 --client端通信口

15672 – 管理界面ui端口
25672 – server间内部通信口

3.2测试

我们只要访问15672端口,就可以看到rabbitmq的管理端的登录页

默认账号密码guest

image-20220530114335704

connections:无论生产者还是消费者,都需要与RabbitMQ建立连接后才可以完成消息的生产和消费,在这里可以查看连接情况

channels:通道,建立连接后,会形成通道,消息的投递获取依赖通道。

Exchanges:交换机,用来实现消息的路由

Queues:队列,即消息队列,消息存放在队列中,等待消费,消费后被移除队列。

端口:

5672: rabbitMq的编程语言客户端连接端口

15672:rabbitMq管理界面端口

25672:rabbitMq集群的端口

四、RabbitMQ运行机制

AMQP中的消息路由由

  • AMQP中消息的路由过程和Java开发熟悉的JMS存在一些差别,AMQP中增加了Exchange和Binding的角色。生产者把消息发布到Exchange上,消息最终到达队列并被消费者接收,而binding决定交换器的消息应该发送到那个队列。

image-20220530154648303

Exchange类型

  • Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct、tanout、topic、headers。headers匹配AMQP消息的header而不是路由键,headers交换器和direct交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型:

    image-20220530160047035

direct和headers是JMS的点对点通信的实现 tanout和topic是发布订阅的实现 headers性能比较低下不建议使用

direct和fanout和topic三个交换机,交换机类型不同,路由到地方就不一样

image-20220530162612650

image-20220530162511281

五、RabbitMQ的图形用户界面使用

添加用户

如果不使用guest,我们也可以直接创建一个用户;

image-20220530165116895

1、 超级管理员(administrator)

可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。

2、 监控者(monitoring)

可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)

3、 策略制定者(policymaker)

可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。

4、 普通管理者(management)

仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。

5、 其他

无法登陆管理控制台,通常就是普通的生产者和消费者。

创建一个新的交换机

image-20220530163539961

image-20220530163601867

交换机必须与队列进行绑定才能工作

进入交换机可以看到

image-20220530163701317

默认是没有任何绑定,我们也可以在里面进行消息传输

所以我们想要使用交换机首先绑定一个队列,绑定一个队列就要先创建一个队列

image-20220530163851310

image-20220530163916975

创建好队列现在将交换机与队列进行绑定(交换机也可以根交换机绑定,也可以跟队列绑定)

image-20220530164052078

进行绑定

image-20220530164120889

接下来我们根据如下图来在RabbitMQ里面创建所有的交换机,队列,以及绑定好他们之间的关系,可以进行测试下各个关系都是怎么进行工作的

image-20220530165236927

首先先创建四个队列以便测试

image-20220530170947645

接着创建交换机image-20220530171015316

使用该交换机绑定四个队列

image-20220530171219639

进入队列可以看到

image-20220530171342515

消息ready为0,消息总量total为0,未回复消息unacked也为0

想要发消息,首先将消息发送给交换机

下面我们是我们直接交换机的演示,就是路由键精确写什么,我们就路由到哪里。direct exchange

image-20220530171542416

发送消息指定我们的路由 根据绑定交换机队列指定的路由不一样而进行开发

image-20220530171934067

对路由为hhxy.news的消息队列进行发送消息

image-20220530172107936
就可以发现hhxy.news中确实有消息发送 ready表示有一个消息准备好了但还没接收

如果想要查看消息队列中的消息进入hhxy.news队列里面,再进入get Message中

image-20220530172336872

Ack Mode回复模式 Nack message requeue true我们把消息拿来,不告诉RabbitMQ我收到消息了,RabbitMQ就会把消息重新存放到队列里面,让别人拿到。

image-20220530172637782

接着我们发现看完消息后,消息还在所以我们换一种类型查看消息image-20220530172717181

image-20220530172924833

通过Automatic ack来获取消息

image-20220530173003181

查看消息成功,当我们再次点击获取消息时会发现

image-20220530173029828

image-20220530173043232

就会发现消息已经不在队列中了

fanout exchange 广播型交换机

image-20220530180402456

image-20220530180450965

同样我们为该交换器绑定消息队列

image-20220530180811901

发送消息查看消息队列谁能接收到消息

image-20220530181012099

可以发现所有的消息队列都获取到数据了

image-20220530181044536

可以说我们发消息无论我们的路由键是什么,我们的消息队列都会有消息

就算我们发消息不写路由键,所有消息队列都会收到

image-20220530181327157

Topic exchange 主题型交换机

首先我们创建一个交换机topic

根据hhxy.#,#.news,#.emps的路由键来绑定交换机

image-20220530182255400

#就代表可以有单词,可以没有 *就代表必须有

现在开始发送消息 观察具体哪一个消息队列获取到消息

假设我们发送一个路由键为hhxy.news的消息

image-20220530182455991

消息队列为1的,当我发送了消息就加1如下图

image-20220530182709377

因为hhxy.news符合路由键中四个要求所以所有的都会加1

我们再发送一个消息这次以.news结尾的路由键 hello.news

image-20220530183058205

根据情况推论,hello.news只符合以上四种路由键中hhxyxueyuan.news的路由键*.news,所以应该只要hhxyxueyuan.news的消息队列会加1,我们测试一下结果如下

image-20220530183241888

果然如同我们猜想,hhxyxueyuan.news消息队列加1了

可以看出topic exchange相当于模糊匹配

五、RabbitMQ整合

1,引入spring-boot-starter-amqp

2,application.yml配置

3,测试RabbitMQ

​ 1,AmqpAdmin:管理组件

​ 2,RabbitTemplate:消息发送处理组件

/**
 * 使用RabbitMQ
 * 1,引入了amqp场景 RabbitAutoConfiguration就会自动生效
 * 2,给容器中自动配置了
 *   RabbitTemplate、AmqpAdmin、CachingConnectionFactory、RabbitMessagingTemplate
 *   所有的属性都是spring.rabbitmq
 *   @ConfigurationProperties(prefix = "spring.rabbitmq")
 *   public class RabbitProperties
 *
 *
 * 3,给配置文件中配置spring.rabbitmq信息
 * 4,@EnableRabbit:@EnableXxxxx  开启功能
 * 5,监听消息:使用@RabbitListener:必须有@EnableRabbit
 * @RabbitListener:类+方法上(监听哪些队列即可)
 * RabbitHandler:标在方法上(重载区分不同的消息)
 *
 */

给RabbitMQ放一些连接工厂,从里面获取连接

image-20220530185410754

放入组件

image-20220530185602573

image-20220530185624672

image-20220530185732271

配置application.yml可以查看

RabbitAutoConfiguration的代码中 RabbitProperties

image-20220530191007374

配置文件我们写在application.properties中

spring.rabbitmq.host=192.168.172.128
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/

其他的暂时不写,因为RabbitProperties.class中默认定义了很多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值