简介

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

1、大多应用中,可通过消息服务中间件来提升系统异步通信、扩展解耦的能力

2、消息服务中两个重要概念

消息代理(message broker)和目的地(destination)

消息代理:指的是一个代理代替我们发送、接收消息

  • 简单理解就是,安装了消息中间件的服务器,发消息得用它发,接收消息也得连上它,才能拿到

目的地:指消息的目标位置

发消息的整体流程

当消息发送者要发送消息时,这个消息会先发给消息代理(也就是消息中间件服务器),消息代理会发到我们指定的目的地

3、消息队列主要有两种形式的目的地

  1. 队列(queue):点对点消息通信(point-to-point)
  2. 主题(topic):发布(publish)/订阅(subscribe)消息通信

只要是消息中间件,一定会有这两种模式

4、点对点式通信(队列式)

消息发送者发送消息,首先发送给消息代理, 消息代理收到消息之后,如果消息发送者说要发给一个队列,消息代理就会将其放入一个队列中,队列都是先进先出,消息先进来就会先取到,

别人如果要获取队列中的消息,怎么办?

别人可以监听队列里的消息内容,一旦队列里面有消息,这个人就可以拿到消息 ,

总结

  • 消息有唯一的发送者、接收者, 也就是说谁发送消息这是肯定的,谁最终拿到消息这也是肯定的,但是并不是说只能有一个接收者 ,可以很多人都来接收队列里面的消息,队列可以允许很多人同时监听消息
  • 但是如果是点对点式(队列式),消息放到队列之后,最终只会交给一个人, 谁先抢到,就是谁的
  • 消息一旦被别人抢到,就会从队列中移除,队列里面就没有这个消息了

5、发布订阅式

发送者(发布者)先将消息发给消息代理, 消息代理要将消息发送到主题,这个主题可以有多个接收者(订阅者)同时监听(订阅)
,跟队列一样,

如果是队列,那么多个人监听,最终只会有一个人收到消息,

但如果是一个主题,主题是一种发布订阅模式,只要消息一到达,那么所有订阅消息的人都能收到消息

6、消息队列规范

JMS(Java Message Service)JAVA消息服务

基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现

7、消息队列协议

AMQP(Advanced Message Queuing Protocol)

  • 高级消息队列协议,也是一个消息代理的规范,兼容JMS
  • RabbitMQ是AMQP的实现

8、规范与协议的对比

JMS(Java Message Service) AMQP(Advanced Message Queuing Protocol)
定义 Java api 网络线级协议
跨语言
跨平台
Model 提供两种消息模型:
(1)、Peer-2-Peer
(2)、Pub/sub
提供了五种消息模型:
(1)、direct exchange
(2)、fanout exchange
(3)、topic change
(4)、headers exchange
(5)、system exchange
本质来讲,后四种和JMS的pub/sub模型没有太大差别,
仅是在路由机制上做了更详细的划分;
支持消息类型 多种消息类型:
TextMessage
MapMessage
BytesMessage
StreamMessage
ObjectMessage
Message (只有消息头和属性)
byte[]
当实际应用时,有复杂的消息,可以将消息序列化后发
送。
综合评价 JMS 定义了JAVA API层面的标准;在java体系中,
多个client均可以通过JMS进行交互,不需要应用修
改代码,但是其对跨平台的支持较差;
AMQP定义了wire-level层的协议标准;天然具有跨平
台、跨语言特性。

9、Spring支持

  • spring-jms提供了对JMS的支持
  • spring-rabbit提供了对AMQP的支持
  • 需要ConnectionFactory的实现来连接消息代理
  • 提供JmsTemplate、RabbitTemplate来发送消息
  • @JmsListener(JMS)@RabbitListener(AMQP)注解在方法上监听消息代理发布的消息
  • @EnableJms@EnableRabbit开启支持

10、Spring Boot自动配置

  • JmsAutoConfiguration
  • RabbitAutoConfiguration

RabbitMQ工作流程

image.png

  1. 无论是生产者(Publisher)想要发消息(Message),还是消费者(Consumer)要接消息(Message),它们都必须跟 RabbitMQ 建立一条连接(Connection)
  2. 所有的收发数据都需要在连接(Connection)里面开辟信道(Channel)进行收发,想要收发的都是消息(Message),所以我们要构造一个消息(Message),消息有头有体,头相当于是对参数的一些设置、命令,体就是消息的真正内容,而消息里面最重要的一个就是路由键(routing-key)
  3. 我们将消息指定好路由键(routing-key)要发给谁以后,消息(Message)先来到消息代理(Broker)指定的一个虚拟主机(Virtual Host)里边, 由虚拟主机(Virtual Host)里边指定交换机(Exchange)
  4. 这就相当于我们要发消息(Message)的时候,我们还要指定好要发给哪个交换机(Exchange)
  5. 由指定的交换机(Exchange)收到消息以后,它根据我们指定的路由键(routing-key),通过交换机跟其它队列(Queue)的绑定关系,将这个消息放到哪个队列(Queue)
  6. 然后消费者(Consumer)就会监听这个队列,队列里面的内容就会被消费者(Consumer)实时拿到,当然也是通过信道(Channel)拿到的

建立长连接的好处

一旦消费者(Consumer)出现了问题,宕机或者各种,连接中断了,RabbitMQ就会实时的感知有消费者下线,消息没办法派发,它就会再次存储到队列(Queue)中,不会造成大面积的消息丢失,

Message

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

Publisher

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

Exchange

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

Queue

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

Binding

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

Connection

网络连接,比如一个TCP连接。

Channel

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

Consumer

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

Virtual Host

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

Broker

表示消息队列服务器实体

image.png

RabbitMQ运行机制

image.png

消息生成者发送一个消息,消息先发给消息代理(Broker),由代理先将消息交给(Exchange)交换机,然后这个交换机下面可能会绑定(Bingdings)了很多队列(Queues),所以一个交换机跟很多种队列都有绑定关系,

一个交换机可以绑定很多队列,一个队列也可以被多个交换机绑定,所以它们之间有非常复杂的绑定关系,

接下来就由交换机决定,消息要按照什么绑定关系路由给哪个消息队列,这个关系就是消息路由

这个路由是根据一开始发的路由键(routing-key)指定的,由于这个消息是先发送给交换机,所以交换机不一样,它绑定关系不一样,最终路由到的地方也不一样,消费者收到的消息就不一样