黑马学SpringAMQP

目录:

(1)SpringAMQP的基本介绍

(2)SpringAMQP-入门案例的消息发送

(3) SpringAMQP-入门案例的消息接收

(4)SpringAMQP-WorkQueue模型

(5)SpringAMPQ-发布订阅模型介绍

(6)SpringAMQP-FanoutExchange

(7)SpringAMQP-DirectExchange

(8)SpringAMQP-TopicExchange

(9)SpringAMQP-消息转换器

 (10)面试知识点:


(1)SpringAMQP的基本介绍

上面的官方提供的简单队列模型消息发送与接收的api,写起来非常的麻烦,而SpringAMQP可以大大简化消息发送和接收的api

黑马学SpringAMQP_第1张图片

黑马学SpringAMQP_第2张图片

 黑马学SpringAMQP_第3张图片

(2)SpringAMQP-入门案例的消息发送

黑马学SpringAMQP_第4张图片 黑马学SpringAMQP_第5张图片

 黑马学SpringAMQP_第6张图片黑马学SpringAMQP_第7张图片

 黑马学SpringAMQP_第8张图片

 这里我们使用单元测试来做的,将来肯定不是单元测试,是在微服务里做业务,有人支付成功了,我想发送一个消息,在支付之后的业务里加上,发送消息的代码就可以了。

首先配置文件进行配置:

黑马学SpringAMQP_第9张图片

编写测试类:发送消息 :是Springboot项目,单元 测试需要加两个注解:

黑马学SpringAMQP_第10张图片 黑马学SpringAMQP_第11张图片

对列中接收了一条消息: 

黑马学SpringAMQP_第12张图片 进入这个对列,查看一下:

黑马学SpringAMQP_第13张图片

 黑马学SpringAMQP_第14张图片

(3) SpringAMQP-入门案例的消息接收

黑马学SpringAMQP_第15张图片

第一步引依赖,在父工程已经做了,这里不用在引了

消费者去监听消息,Spring已经帮助我们跟MQ建立了连接,连接的事不用管了,唯一需要管的事是,我要去监听那个对列,监听到这个队列后干什么事

首先进行配置配置文件:

黑马学SpringAMQP_第16张图片

 创建类:

黑马学SpringAMQP_第17张图片

这个类是Spring中的Bean,接收消息是有Spring来处理的,所以启动主启动类,就可以了:

黑马学SpringAMQP_第18张图片

 可以看到消息接收成功了黑马学SpringAMQP_第19张图片

 浏览器对类中的消息就没了:消息消费完就干掉了黑马学SpringAMQP_第20张图片

黑马学SpringAMQP_第21张图片

 (4)SpringAMQP-WorkQueue模型

黑马学SpringAMQP_第22张图片

 这里有两个消费者,有一条消息,消费者一接收到,消费完就会删除,消费者二就不会拿到这个消息,如果有50条消息,不会每个人50条,而是他两各自处理一部分,合起来是50条

只有一个消费者不行吗?比如这个消费者每秒处理40条消息,发送者每秒发送50条,那么这个消费者消费不完,每秒会多出来10个消息没人处理,这个消息怎么办呢?只能堆积在队列当中,那么队列是有存储上限的,最终会堆积满的,有两个消费者的话会不会堆积消息

黑马学SpringAMQP_第23张图片

 黑马学SpringAMQP_第24张图片

黑马学SpringAMQP_第25张图片

从测试类里面,定义第二个方法: 

黑马学SpringAMQP_第26张图片

 黑马学SpringAMQP_第27张图片黑马学SpringAMQP_第28张图片

 消费者让他们分被睡ji

黑马学SpringAMQP_第29张图片

 启动消息的发送者的代码:消息平均的分配给这两个消费者,消费者1拿的是偶数,消费者二拿的是奇数,它没有考虑消费者的消费能力,平均接收,这是MQ的一种机制决定的,消息的预取机制

黑马学SpringAMQP_第30张图片

 消息预取:是先把消息都拿过来,有多小消息拿多少,不管能不能消费 这样消息会先平均的分配到消费者黑马学SpringAMQP_第31张图片黑马学SpringAMQP_第32张图片

在消费者的配置文件中加这个配置:每次都取一条消息,取完再拿,这样就不会出现消息先预取过来的情况了

黑马学SpringAMQP_第33张图片

 重新启动消费者的启动类:

黑马学SpringAMQP_第34张图片

重新发送消息:消费者一消费了大量的消息,消费者二消费的比较慢,它只消费了几条消息

黑马学SpringAMQP_第35张图片 黑马学SpringAMQP_第36张图片

 这样就起到了能者多劳的效果了,消费者一消费能力块,所以消费的消息多

黑马学SpringAMQP_第37张图片

(5)SpringAMPQ-发布订阅模型介绍

简单模型、工作对列模型发送的消息,他们有一个共同的特点,就是它发送的消息只能被一个消费者消费,一旦消费完就会从对列中删除

它是无法满足课程开始时的需求,用户支付完,去通知其他服务:订单服务、存储服务、短信服务,这三个服务各自去完成自己的业务,也就是说你发送的这条消息,需要被三个消费者服务都接收到 ,那怎么办?就需要用到发布与订阅

黑马学SpringAMQP_第38张图片

以前的模型是直接发送给对列,而这里是发送给交换机,交换机再把消息转发到队列当中,消息的发送者不需要队列的存在,交换机可以把消息转发给多个队列,如果转发给多个对列,就实现了一个消息被多个消费者消费了,到底交换机发给一个对列还是多个队列,是由交换机的类型决定的,分为三种交换机,他们只负责消息的转发

(6)SpringAMQP-FanoutExchange

黑马学SpringAMQP_第39张图片

黑马学SpringAMQP_第40张图片 黑马学SpringAMQP_第41张图片

黑马学SpringAMQP_第42张图片 黑马学SpringAMQP_第43张图片

黑马学SpringAMQP_第44张图片黑马学SpringAMQP_第45张图片

 交换机:

 进入这个交换机:看到了绑定关系黑马学SpringAMQP_第46张图片

 队列:

黑马学SpringAMQP_第47张图片

黑马学SpringAMQP_第48张图片黑马学SpringAMQP_第49张图片 

添加: 

黑马学SpringAMQP_第50张图片

黑马学SpringAMQP_第51张图片

 黑马学SpringAMQP_第52张图片

黑马学SpringAMQP_第53张图片

黑马学SpringAMQP_第54张图片

 启动消费者主启动类,运行发送者:黑马学SpringAMQP_第55张图片

 黑马学SpringAMQP_第56张图片

(7)SpringAMQP-DirectExchange

黑马学SpringAMQP_第57张图片 黑马学SpringAMQP_第58张图片

 黑马学SpringAMQP_第59张图片

 黑马学SpringAMQP_第60张图片

 消费者:

 黑马学SpringAMQP_第61张图片

黑马学SpringAMQP_第62张图片

黑马学SpringAMQP_第63张图片 黑马学SpringAMQP_第64张图片

 黑马学SpringAMQP_第65张图片

发送者: 

 黑马学SpringAMQP_第66张图片

 发送签名blue,相同的签名key才能接收消息:黑马学SpringAMQP_第67张图片

 黑马学SpringAMQP_第68张图片

 换成签名key为yellow的,相同的key才能接收消息:黑马学SpringAMQP_第69张图片

 黑马学SpringAMQP_第70张图片

发送red的签名key,消费者都能接收到 

黑马学SpringAMQP_第71张图片 黑马学SpringAMQP_第72张图片

黑马学SpringAMQP_第73张图片

(8)SpringAMQP-TopicExchange

黑马学SpringAMQP_第74张图片

黑马学SpringAMQP_第75张图片

 黑马学SpringAMQP_第76张图片

黑马学SpringAMQP_第77张图片

黑马学SpringAMQP_第78张图片

黑马学SpringAMQP_第79张图片 运行

黑马学SpringAMQP_第80张图片

 黑马学SpringAMQP_第81张图片

黑马学SpringAMQP_第82张图片

 黑马学SpringAMQP_第83张图片

黑马学SpringAMQP_第84张图片

运行:

黑马学SpringAMQP_第85张图片

黑马学SpringAMQP_第86张图片只有queue1收到消息: 黑马学SpringAMQP_第87张图片

 黑马学SpringAMQP_第88张图片

(9)SpringAMQP-消息转换器

 黑马学SpringAMQP_第89张图片

 黑马学SpringAMQP_第90张图片

 黑马学SpringAMQP_第91张图片

 黑马学SpringAMQP_第92张图片

 黑马学SpringAMQP_第93张图片

 黑马学SpringAMQP_第94张图片

 黑马学SpringAMQP_第95张图片黑马学SpringAMQP_第96张图片

 黑马学SpringAMQP_第97张图片

 黑马学SpringAMQP_第98张图片

 查看消息:发现数据不对,进行了序列话,我们rabbitMQ只支持字节,Spring允许我们发object的对象,说明啊,它会将我们的对象做序列化,用的是jdk的序列化方式,这个序列化有缺点:性能比较差、安全性有问题,数据长度长黑马学SpringAMQP_第99张图片

 在父工程中引入依赖:

黑马学SpringAMQP_第100张图片

发送消息: 

黑马学SpringAMQP_第101张图片

在主启动类中声明Bean,他也是一个配置Bean

 黑马学SpringAMQP_第102张图片

先清除消息:

黑马学SpringAMQP_第103张图片

重新发送消息:

黑马学SpringAMQP_第104张图片 浏览器查看:

黑马学SpringAMQP_第105张图片

 接收消息:

黑马学SpringAMQP_第106张图片

引来已经在父工程引入过了,创建Bean:

黑马学SpringAMQP_第107张图片

 黑马学SpringAMQP_第108张图片

黑马学SpringAMQP_第109张图片

 黑马学SpringAMQP_第110张图片

黑马学SpringAMQP_第111张图片

面试知识点:

(10)消息队列-如何顺序消费?

黑马学SpringAMQP_第112张图片

 黑马学SpringAMQP_第113张图片

 (11)消息队列如何解决消息丢失问题?

黑马学SpringAMQP_第114张图片

因此如何保证MQ不丢失消息,可以从这三个阶段阐述:

生产者保证不丢消息
存储端不丢消息
消费者不丢消息
3.1 生产者保证不丢消息
生产端如何保证不丢消息呢?确保生产的消息能到达存储端。

如果是RocketMQ消息中间件,Producer生产者提供了三种发送消息的方式,分别是:

同步发送
异步发送
单向发送
生产者要想发消息时保证消息不丢失,可以:

采用同步方式发送,send消息方法返回成功状态,就表示消息正常到达了存储端Broker。
如果send消息异常或者返回非成功状态,可以重试。
可以使用事务消息,RocketMQ的事务消息机制就是为了保证零丢失来设计的
3.2 存储端不丢消息
如何保证存储端的消息不丢失呢?确保消息持久化到磁盘。大家很容易想到就是刷盘机制。

刷盘机制分同步刷盘和异步刷盘:

生产者消息发过来时,只有持久化到磁盘,RocketMQ的存储端Broker才返回一个成功的ACK响应,这就是同步刷盘。它保证消息不丢失,但是影响了性能。
异步刷盘的话,只要消息写入PageCache缓存,就返回一个成功的ACK响应。这样提高了MQ的性能,但是如果这时候机器断电了,就会丢失消息。
Broker一般是集群部署的,有master主节点和slave从节点。消息到Broker存储端,只有主节点和从节点都写入成功,才反馈成功的ack给生产者。这就是同步复制,它保证了消息不丢失,但是降低了系统的吞吐量。与之对应的就是异步复制,只要消息写入主节点成功,就返回成功的ack,它速度快,但是会有性能问题。

3.3 消费阶段不丢消息
消费者执行完业务逻辑,再反馈会Broker说消费成功,这样才可以保证消费阶段不丢消息。

(12)消息队列如何保证消息的顺序性?

消息的有序性,就是指可以按照消息的发送顺序来消费。有些业务对消息的顺序是有要求的,比如先下单再付款,最后再完成订单,这样等。假设生产者先后产生了两条消息,分别是下单消息(M1),付款消息(M2),M1比M2先产生,如何保证M1比M2先被消费呢。

黑马学SpringAMQP_第115张图片

为了保证消息的顺序性,可以将M1、M2发送到同一个Server上,当M1发送完收到ack后,M2再发送。如图:

黑马学SpringAMQP_第116张图片

 这样还是可能会有问题,因为从MQ服务器到消费端,可能存在网络延迟,虽然M1先发送,但是它比M2晚到。

黑马学SpringAMQP_第117张图片

那还能怎么办才能保证消息的顺序性呢?将M1和M2发往同一个消费者,且发送M1后,等到消费端ACK成功后,才发送M2就得了。

黑马学SpringAMQP_第118张图片

消息队列保证顺序性整体思路就是这样啦。比如Kafka的全局有序消息,就是这种思想的体现: 就是生产者发消息时,1个Topic只能对应1个Partition,一个 Consumer,内部单线程消费。

但是这样吞吐量太低,一般保证消息局部有序即可。在发消息的时候指定Partition Key,Kafka对其进行Hash计算,根据计算结果决定放入哪个Partition。这样Partition Key相同的消息会放在同一个Partition。然后多消费者单线程消费指定的Partition。


黑马学SpringAMQP_第119张图片

黑马学SpringAMQP_第120张图片

 .如何保证数据一致性,事务消息如何实现?

一条普通的MQ消息,从产生到被消费,大概流程如下:

黑马学SpringAMQP_第121张图片

生产者产生消息,发送带MQ服务器
MQ收到消息后,将消息持久化到存储系统。
MQ服务器返回ACk到生产者。
MQ服务器把消息push给消费者
消费者消费完消息,响应ACK
MQ服务器收到ACK,认为消息消费成功,即在存储中删除消息。
我们举个下订单的例子吧。订单系统创建完订单后,再发送消息给下游系统。如果订单创建成功,然后消息没有成功发送出去,下游系统就无法感知这个事情,出导致数据不一致。

黑马学SpringAMQP_第122张图片

生产者产生消息,发送一条半事务消息到MQ服务器
MQ收到消息后,将消息持久化到存储系统,这条消息的状态是待发送状态。
MQ服务器返回ACK确认到生产者,此时MQ不会触发消息推送事件
生产者执行本地事务
如果本地事务执行成功,即commit执行结果到MQ服务器;如果执行失败,发送rollback。
如果是正常的commit,MQ服务器更新消息状态为可发送;如果是rollback,即删除消息。
如果消息状态更新为可发送,则MQ服务器会push消息给消费者。消费者消费完就回ACK。
如果MQ服务器长时间没有收到生产者的commit或者rollback,它会反查生产者,然后根据查询到的结果执行最终状态。

如何保证数据一致性呢?可以使用事务消息。


消息队列的应用场景?

为什么使用消息队列。你可以回答以下这几点:
1.应用解耦
2.流量削峰
3.异步处理
4.消息通讯
5.远程调用

黑马学SpringAMQP_第123张图片

黑马学SpringAMQP_第124张图片 黑马学SpringAMQP_第125张图片

 黑马学SpringAMQP_第126张图片

黑马学SpringAMQP_第127张图片 黑马学SpringAMQP_第128张图片

你可能感兴趣的:(spring,spring,boot,java)