1. RabbitMQ是什么东西
RabbitMQ是采用 Erlang 语言开发的 AMQP(Advanced Message Queuing Protocol,高级消息队例协议)的开源实现。它最初起源于金融系统,用于在分布式系统中存储转发消息。
RabbitMQ的具体特点可以概括为以下几点:
- 可靠性:RabbitMQ 使用一些机制来保证可靠性,如
持久化
、传输确认
及发布确认
等。 - 灵活的路由:在消息进入队列之前,通过
Exchange
来路由消息。 - 扩展性:多个MQ节点可以组成一个
集群
,可以根据根据实际业务情况动态扩展集群。 - 高可用性:队列可以在集群机器上设置
镜像
,使得部分节点出现问题时队列仍然可用。 - 多种协议:RabbitMQ 支持多种消息队列协议,除了AMQP外,还支持STOMP、MQTT等。
- 多语言客户端:RabbitMQ 几乎支持所有常用语言,比如 php、Python、C等;
- 管理界面:RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 、节点等。(Web管理界面也是一种插件,还可以通过HTTP API进行管理)
- 插件机制:RabbitMQ 提供了许多插件,来从多方面进行扩展,也可以编写自己的插件。
2. RabbitMQ相关概念
2.1 基本概念
RabbitMQ整体上是一个生产者与消费者模型
,主要负责接收、存储和转发消息。
RabbitMQ模型架构
如下图:
上图中涉及的概念主要有:
(1)消息(Message)
消息
一般可以包含2个部分:消息体
和消息属性
。消息体
(也成payload)一般是带有业务逻辑结构的数据,比如Json字符串;消息属性
用于表述消息,比如消息对应的Exchange名称和RoutingKey。
(2)生产者(Producer)
生产者
就是发送消息的一方。
- 个人理解本质上就是一个channel,channel执行了 basicPublish 的API。
(3)消费者(Consumer)
消费者
就是接收消息的一方。
- 个人理解本质上就是一个channel,channel执行了basicConsume的API。
(4)队列(Queue)
队列
在RabbitMQ中用于存储消息
。生产者所发送的消息最终被投递到队列中,消费者从队列获取消息并消费。
- RabbitMQ中消息只存储在队列中,Exchange只做路由、不存储消息。
- 所有队列都绑定到默认交换机exchange="",并且绑定时使用的routingKey=queueName
(5)交换机(Exchange)
生产者将消息发送给Exchange
,Exchange再将消息路由给队列。
- 消息的路径是:
生产者
->交换机
->队列
。
(6)路由键(RoutingKey)
生产者在发送消息时,需要指定Exchange和RoutingKey
,并且队列和Exchange之间的绑定关系也通过RoutingKey来标识。
(7)绑定(Binding)
绑定
可以理解为一个三元组<queueName, exchangeName, bindingKey>,表示将queue用bindingKey绑定到exchange,该exchange收到的消息时,会根据exchange类型和消息的routingKey将消息路由到符合的队列。
- 也可以将交换机绑定到交换机。
(8)节点(Broker)
节点
是一个RabbitMQ服务器实例,一个集群中有多个节点,这些节点可以在多台机器上,也可以在同一台机器上(端口不同)。
(9)虚拟主机(Virtual Host)
虚拟主机
是共享相同身份认证和加密环境的独立服务器域。不同虚拟主机之间是相互隔离的,拥有独立的交换机、队列、绑定等。
- 可以将
虚拟主机与节点之间的关系
理解为数据库与mysql之间的关系
,一台mysql服务上有不同的数据库。
(10)连接(Connection)
Connection
是客户端与服务器之间建立的一个网络连接。
(11)信道(Channel)
Channel
可以理解为一种轻量连接,多个channel共享一个Connection。
由于创建和销毁Connection的开销大,所以在Connection内部建立Channel。
- 不同的Channel之间
互相隔离
; - Channel是
双向
的数据通道。 - RabbitMQ几乎所有操作均是
通过Channel完成
,包括发送消息、创建队列、交换机等、消费消息。先创建Connection、然后创建Channel,再使用Channel执行操作。
2.2 Exchange
2.2.1 交换机参数
以php Channel接口API来说明创建交换机的主要参数。
channel.exchangeDeclare(exchange, type);.// 第一个参数,exchange:交换机名称。数据类型:String
// 第二个参数,type:交换机的类型(direct/topic/fanout)。数据类型:String
2.2.2 交换机类型
RabbitMQ常用交换机类型有fanout
、direct
、topic
四种。
2.2.2.1 广播模式(fanout)
当一个交换机是广播模式的话,所有绑定到该交换机上的队列(或交换机)都能收到路由的消息,不论bindingKey的取值。
- 对
队列
而言,无论队列与交换机绑定时bindingkey
取值是什么、也不论生产者发送消息时的routingkey
是什么,该队列都可以收到广播交换机上所有消息。 - 对于绑定到广播交换机上的
交换机
而言,同样如此。
假设Exchange1是广播交换机,Exchange2是direct交换机,队列Queue1、Queue2绑定到Exchange2交换机。那么Exchange2可以收到Exchange1上所有消息,但是队列Queue1和Queue2只能收到routingKey(生产者设定)与bindingKey一致的消息。
2.2.2.2 direct模式
direct类型交换机会将消息路由到bindingKey与routingKey完全一致
的队列上。(不再特别讨论交换机绑定到交换机的情况)
- 一个队列可以使用不同的routingKey绑定到交换机多次,用于接收多种消息。比如对于消息时日志、日志分不同级别,queue1可以配置成接收debug、warning、info、error四种消息,queue2可以配置成只接收error消息。
2.2.2.3 topic模式
当routingKey中采用点号
“.”分割时,bindingKey可以表现为类似正则表达式
形式,此时队列可以接收到符合bindingKey规则的多个routingKey的消息,而不用像direct模式一样进行多次绑定。
- 生产者发送消息时,使用的routingKey是完整的,且每个单词间用.分割。
- bindingKey中可以使用特殊字符*和#,*用于匹配一个单词,#用于匹配零或多个单词。
如下图,对于routingKey为quick.orange.rabbit
、lazy.orange.elephant
、quick.orange.fox
、lazy.brown.fox
、lazy.pink.rabbit
,Q1可以收到前3个routing Key的消息,Q2可以收到第1、2、4、5个routingKey的消息。
2.2.2.3 topic模式
当routingKey中采用点号
“.”分割时,bindingKey可以表现为类似正则表达式
形式,此时队列可以接收到符合bindingKey规则的多个routingKey的消息,而不用像direct模式一样进行多次绑定。
- 生产者发送消息时,使用的routingKey是完整的,且每个单词间用.分割。
- bindingKey中可以使用特殊字符*和#,*用于匹配一个单词,#用于匹配零或多个单词。
如下图,对于routingKey为quick.orange.rabbit
、lazy.orange.elephant
、quick.orange.fox
、lazy.brown.fox
、lazy.pink.rabbit
,Q1可以收到前3个routing Key的消息,Q2可以收到第1、2、4、5个routingKey的消息。