初识 RabbitMQ
- [1.认识 RabbitMQ](#1.认识 RabbitMQ)
-
- [1.1 介绍](#1.1 介绍)
- [1. 2.使用场景](#1. 2.使用场景)
-
- [1.2.1 推送通知](#1.2.1 推送通知)
- [1.2.2 异步任务](#1.2.2 异步任务)
- [1.2.3 多平台应用的通信](#1.2.3 多平台应用的通信)
- [1.2.4 消息延迟](#1.2.4 消息延迟)
- [1.2.5 远程过程调用](#1.2.5 远程过程调用)
- [1.3 特性](#1.3 特性)
- 2.基本概念
-
- [2.1 生产者、消费者和代理](#2.1 生产者、消费者和代理)
- [2.2 消息队列](#2.2 消息队列)
- [2.3 交换机](#2.3 交换机)
-
- [2.3.1 direct](#2.3.1 direct)
- [2.3.2 topic](#2.3.2 topic)
- [2.3.3 headers](#2.3.3 headers)
- [2.3.4 fanout](#2.3.4 fanout)
- [2.4 绑定](#2.4 绑定)
- [2.5 通道](#2.5 通道)
- [2.6 消息确认](#2.6 消息确认)
1.认识 RabbitMQ
1.1 介绍
RabbitMQ 是开源的 高级消息队列协议(Advanced Message Queueing Protocol
,AMQP
)的实现,用 Erlang 语言编写,支持多种客户端。
RabbitMQ 是目前应用相当广泛的消息中间件(其他同类的消息处理中间件有 ActiveMQ、Kafka 等)。在企业级应用、微服务应用中,RabbitMQ 担当着十分重要的角色。例如,在业务服务模块中 解耦、异步通信、高并发限流、超时业务、数据延迟处理 等都可以使用 RabbitMQ。
1. 2.使用场景
1.2.1 推送通知
发布 / 订阅 是 RabbitMQ 的重要功能。可以用 "发布 / 订阅 " 功能来实现通知功能。消费者(consumer
)一直监听 RabbitMQ 的数据。如果 RabbitMQ 有数据,则消费者会按照 先进先出 规则逐条进行消费。而生产者(producer
)只需要将数据存入 RabbitMQ。这样既降低了不同系统之间的耦合度,也确保了消息通知的及时性,且不影响系统的性能。
"发布 / 订阅 " 功能支持三种模式:一对一、一对多、广播。这三种模式都可以根据规则选择分发的对象。众多消费者可以根据规则选择是否接收这些数据,扩展性非常强。
1.2.2 异步任务
后台系统接到任务后,将其分解成多个小任务,只要分别完成这些小任务,整个任务便可以完成。但是,如果某个小任务很费时,且延迟执行并不影响整个任务,则可以将该任务放入消息队列中去处理,以便加快请求响应时间。
如果用户注册会员时有一项需求:发送验证邮件或短信验证码以完成验证,则可以使用 RabbitMQ 的消息队列来实现,这样可以及时提醒用户操作已经成功。等待收到邮件或验证码,然后进行相应的确认,即完成验证。
1.2.3 多平台应用的通信
RabbitMQ 可以用于不同开发语言开发的应用间的通信(如 Java 开发的应用程序需要与 C++ 开发的应用程序进行通信),实现企业应用集成。由于消息队列是无关平台和语言的,而且语义上也不是函数调用,因此 RabbitMQ 适合作为多个应用之间的松耦合的接口,且不需要发送方和接收方同时在线。
不同语言的软件解耦,可以最大限度地减少程序之间的相互依赖,提高系统可用性及可扩展性同时还增加了消息的可靠传输和事务管理功能。
RabbitMQ 提供两种事务模式:
- AMQP 事务模式
- Confirm 事务模式
1.2.4 消息延迟
利用 RabbitMQ 消息队列延迟功能,可以实现订单、支付过期定时取消功能。因为延迟队列存储延时消息,所以,当消息被发送以后,消费者不是立即拿到消息,而是等待指定时间后才拿到这个消息进行消费。
当然,死信、计时器、定时任务也可以实现延迟或定时功能,但是需要开发者去处理。
要实现消息队列延迟功能,一般采用官方提供的插件 rabbitmq_delayed_message_exchange
来实现,但 RabbitMQ 版本必须是 3.5.8 3.5.8 3.5.8 版本以上才支持该插件。如果低于这个版本则可以利用 死信 来完成。
1.2.5 远程过程调用
在实际的应用场景中,有时需要一些同步处理,以等待服务器端将消息处理完成后再进行下步处理,这相当于 RPC
(Remote Procedure Call
,远程过程调用)。RabbitMQ 也支持 RPC。
1.3 特性
RabbitMQ 具有以下特性。
- 信息确认:RabbitMQ 有以下两种应答模式。
- 自动应答:当 RabbitMQ 把消息发送到接收端,接收端从队列接收消息时,会自动发送应答消息给服务器端。
- 手动应答:需要开发人员手动调用方法告诉服务器端已经收到。
如果实际场景中对个别消息的丢失不是很敏感,则选用自动应答比较理想。如果是一个消息都不能丢的场景,则需要选用手动应答,在正确处理完以后才应答。如果选择了自动应答,那消息重发这个功能就没有了。
- 队列持久化:队列可以被持久化,但是否为持久化,要看持久化设置。
- 信息持久化:设置
properties.DeliveryMode
值即可。默认值为 1 1 1,代表不是持久的, 2 2 2 代表持久化。 - 消息拒收:接收端可以拒收消息,而且在发送
reject
命令时,可以选择是否要把拒收的消息重新放回队列中。 - 消息的 QoS:在接收端设置的。发送端没有任何变化,接收端的代码也比较简单,只需要加上如
channel.BasicQos(0,1,false);
的代码即可。
2.基本概念
2.1 生产者、消费者和代理
RabbitMQ 的角色有以下三种。
- 生产者:消息的创建者,负责创建和推送数据到消息服务器。
- 消费者:消息的接收方,用于处理数据和确认消息。
- 代理:RabbitMQ 本身,扮演 "快递" 的角色,本身不生产消息。
🚀 生产者和消费者并不属于 RabbitMQ,RabbitMQ 只是为生产者和消费者提供发送和接收消息的 API。
2.2 消息队列
Queue(队列)是 RabbitMQ 的内部对象,用于存储生产者的消息直到发送给消费者,也是消费者接收消息的地方。RabbitMQ 中的消息也都只能存储在 Queue 中,多个消费者可以订阅同一个Queue。
Queue 有以下一些重要的属性。
- 持久性:如果启用,则队列将会在 消息协商器(
broker
)重启前都有效。 - 自动删除:如果启用,则队列将会在所有的消费者停止使用之后自动删除掉。
- 惰性:如果没有声明队列,则应用程序调用队列时会导致异常,并不会主动声明。
- 排他性:如果启用,则声明它的消费者才能使用。
2.3 交换机
Exchange(交换机)用于接收、分配消息。生产者先要指定一个 routing key
,然后将消息发送到交换机。这个 routing key
需要与 ExchangeType
及 binding key
联合使用才能最终生效,然后,交换机将消息路由到一个或多个 Queue 中,或丢弃。
在虚拟主机的消息协商器(broker
)中,每个 Exchange 都有唯一的名字。
Exchange 包含 4 4 4 种类型:direct
、topic
、fanout
、headers
。不同的类型代表绑定到队列的行为不同。
🚀 AMQP 规范里还有两种交换机类型:system 与 自定义。
2.3.1 direct
direct
类型的行为是 "先匹配,再投送 "。在绑定队列时会设定一个 routing key
,只有在消息的 routing key
与队列匹配时,消息才会被交换机投送到绑定的队列中。允许一个队列通过一个固定的 routing key
(通常是队列的名字)进行绑定。Direct 交换机将消息根据其 routing key
属性投递到包含对应 key
属性的绑定器上。
Direct Exchange 是 RabbitMQ 默认的交换机模式,也是最简单的模式。它根据 routing key
全文匹配去寻找队列。
2.3.2 topic
按规则转发消息(最灵活)。主题交换机(topic exchange
)转发消息主要根据通配符。队列和交换机的绑定会定义一种路由模式,通配符就要在这种路由模式和路由键之间匹配后,交换机才能转发消息。
在这种交换机模式下,路由键必须是一串字符,用 .
隔开。
路由模式必须包含一个星号 *
,主要用于匹配路由键指定位置的一个单词。
topic
还支持消息的 routing key
,用 *
或 #
的模式进行绑定。*
匹配一个单词,#
匹配 0 0 0 个或多个单词。例如,binding key *.user.#
匹配 routing key
为cn.user
和 us.user.db
,但是不匹配 user.hello
。
2.3.3 headers
它根据应用程序消息的特定属性进行匹配,可以在 binding key
中标记消息为可选或必选。在队列与交换机绑定时,会设定一组键值对规则。消息中也包括一组键值对(headers 属性),当这些键值对中有一对,或全部匹配时,消息被投送到对应队列。
2.3.4 fanout
消息广播的模式,即将消息广播到所有绑定到它的队列中,而不考虑 routing key
的值(不管路由键或是路由模式)。如果配置了 routing key
,则 routing key
依然会被忽略。
2.4 绑定
RabbitMQ 中通过绑定(binding
),将 Exchange 与 Queue 关联起来。这样 RabbitMQ 就知道如何正确地将消息路由到指定的 Queue 了。
在绑定 Exchange 与 Queue 时,一般会指定一个 binding key
。消费者将消息发送给 Exchang 时,一般会指定一个 routing key
。如果 binding key
与 routing key
相匹配,则消息将会被路由对应的 Queue 中。
绑定是生产者和消费者消息传递的连接。生产者发送消息到 Exchange,消费者从 Queue 接收消息,都是根据绑定来执行的。
2.5 通道
有些应用需要与 AMQP 代理建立多个连接。但同时开启多个 TCP(Transmission Control Protocol,传输控制协议)连接会消耗过多的系统资源,并使得防火墙的配置变得更加困难。AMQP 0-9-1
协议用 通道(channel
)来处理多连接,可以把通道理解成 共享一个 TCP 连接的多个轻量化连接。
一个特定通道上的通信与其他通道上的通信是完全隔离的,因此,每个 AMQP 方法都需要携带一个通道号。这样客户端就可以指定此方法是为哪个通道准备的。
2.6 消息确认
消息确认(message acknowledgement
)是指:当一个消息从队列中投递给消费者(consumer)后,消费者会通知一下消息代理(broker),这个过程可以是自动的,也可以由处理消息的应用的开发者执行。当 "消息确认" 启用时,消息代理需要收到来自消费者的确认回执后,才完全将消息从队列中删除。
如果消息无法被成功路由,或被返给发送者并被丢弃,或消息代理执行了延期操作,则消息会被放入一个 死信 队列中。此时,消息发送者可以选择某些参数来处理这些特殊情况。