RabbitMQ基础知识
一、背景
RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现。AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消息通讯的世界里有很多公开标准(如 COBAR的 IIOP ,或者是 SOAP 等),但是在异步消息处理中却不是这样,只有大企业有一些商业实现(如微软的 MSMQ ,IBM 的 Websphere MQ 等),因此,在 2006 年的 6 月,Cisco 、Redhat、iMatix 等联合制定了 AMQP 的公开标准。
二、基础概念
讲解基础概念的前面,我们先来整体构造一个结构图,这样会方便们更好地去理解RabbitMQ的基本原理。
通过上面这张应用相结合的结构图既能够清晰的看清楚整体的send Message
到Receive Message
的一个大致的流程。当然上面有很多名词都相比还没有介绍到,不要着急接下来我们就开始对其进行详细的讲解。
Queue
Queue
(队列)RabbitMQ
的作用是存储消息,队列的特性是先进先出。上图可以清晰地看到Client A
和Client B
是生产者,生产者生产消息最终被送到RabbitMQ
的内部对象Queue
中去,而消费者则是从Queue
队列中取出数据。可以简化成表示为:
生产者Send Message
“A”被传送到Queue
中,消费者发现消息队列Queue
中有订阅的消息,就会将这条消息A读取出来进行一些列的业务操作。这里只是一个消费正对应一个队列Queue
,也可以多个消费者订阅同一个队列Queue
,当然这里就会将Queue
里面的消息平分给其他的消费者,但是会存在一个一个问题就是如果每个消息的处理时间不同,就会导致某些消费者一直在忙碌中,而有的消费者处理完了消息后一直处于空闲状态,因为前面已经提及到了Queue会平分这些消息给相应的消费者。这里我们就可以使用prefetchCount
来限制每次发送给消费者消息的个数。详情见下图所示:
这里的prefetchCount=1
是指每次从Queue
中发送一条消息来。等消费者处理完这条消息后Queue
会再发送一条消息给消费者。
Exchange
我们在开篇的时候就留了一个坑,就是那个应用结构图里面,消费者Client A
和消费者Client B
是如何知道我发送的消息是给Queue1
还是给Queue2
,有没有过这个问题,那么我们就来解开这个面纱,看看到底是个什么构造。首先明确一点就是生产者产生的消息并不是直接发送给消息队列Queue
的,而是要经过Exchange
(交换器),由Exchange
再将消息路由到一个或多个Queue
,当然这里还会对不符合路由规则的消息进行丢弃掉,这里指的是后续要谈到的Exchange Type
。那么Exchange
是怎样将消息准确的推送到对应的Queue
的呢?那么这里的功劳最大的当属Binding
,RabbitMQ
是通过Binding
将Exchange
和Queue
链接在一起,这样Exchange
就知道如何将消息准确的推送到Queue
中去。简单示意图如下所示:
在绑定(Binding
)Exchange
和Queue
的同时,一般会指定一个Binding Key
,生产者将消息发送给Exchange
的时候,一般会产生一个Routing Key
,当Routing Key
和Binding Key
对应上的时候,消息就会发送到对应的Queue中去。那么Exchange
有四种类型,不同的类型有着不同的策略。也就是表明不同的类型将决定绑定的Queue
不同,换言之就是说生产者发送了一个消息,Routing Key
的规则是A,那么生产者会将Routing Key=A
的消息推送到Exchange
中,这时候Exchange
中会有自己的规则,对应的规则去筛选生产者发来的消息,如果能够对应上Exchange
的内部规则就将消息推送到对应的Queue
中去。那么接下来就来详细讲解下Exchange
里面类型。
Exchange Type
我来用表格来描述下类型以及类型之间的区别。
-
fanout
fanout类型的
Exchange
路由规则非常简单,它会把所有发送到该Exchange
的消息路由到所有与它绑定的Queue
中。
上图所示,生产者(P)生产消息1将消息1推送到
Exchange
,由于Exchange Type=fanout
这时候会遵循fanout
的规则将消息推送到所有与它绑定Queue
,也就是图上的两个Queue
最后两个消费者消费。
-
direct
direct类型的
Exchange
路由规则也很简单,它会把消息路由到那些binding key
与routing key
完全匹配的Queue
中
当生产者(P)发送消息时
Rotuing key=booking
时,这时候将消息传送给Exchange
,Exchange
获取到生产者发送过来消息后,会根据自身的规则进行与匹配相应的Queue
,这时发现Queue1
和Queue2
都符合,就会将消息传送给这两个队列,如果我们以Rotuing key=create
和Rotuing key=confirm
发送消息时,这时消息只会被推送到Queue2
队列中,其他Routing Key
的消息将会被丢弃。
-
topic
前面提到的
direct
规则是严格意义上的匹配,换言之Routing Key
必须与Binding Key
相匹配的时候才将消息传送给Queue
,那么topic
这个规则就是模糊匹配,可以通过通配符满足一部分规则就可以传送。它的约定是:-
routing key
为一个句点号“. ”
分隔的字符串(我们将被句点号“. ”
分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”
、“nyse.vmw”
、“quick.orange.rabbit”
-
binding key
与routing key
一样也是句点号“. ”
分隔的字符串 -
binding key
中可以存在两种特殊字符“*”
与“#”
,用于做模糊匹配,其中“*”
用于匹配一个单词,“#”
用于匹配多个单词(可以是零个)
-
当生产者发送消息
Routing Key=F.C.E
的时候,这时候只满足Queue1
,所以会被路由到Queue
中,如果Routing Key=A.C.E
这时候会被同是路由到Queue1
和Queue2
中,如果Routing Key=A.F.B
时,这里只会发送一条消息到Queue2
中。
- headers
headers
类型的Exchange
不依赖于routing key
与binding key
的匹配规则来路由消息,而是根据发送的消息内容中的headers
属性进行匹配。
在绑定Queue
与Exchange
时指定一组键值对;当消息发送到Exchange
时,RabbitMQ
会取到该消息的headers
(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue
与Exchange
绑定时指定的键值对;如果完全匹配则消息会路由到该Queue
,否则不会路由到该Queue
。
该类型的Exchange
没有用到过(不过也应该很有用武之地),所以不做介绍。
这里在对其进行简要的表格整理:
类型名称 | 类型描述 |
---|---|
fanout | 把所有发送到该Exchange 的消息路由到所有与它绑定的Queue 中 |
direct |
Routing Key ==Binding Key
|
topic | 模糊匹配 |
headers |
Exchange 不依赖于routing key 与binding key 的匹配规则来路由消息,而是根据发送的消息内容中的headers 属性进行匹配。 |
补充说明:
ConnectionFactory、Connection、Channel
ConnectionFactory
、Connection
、Channel
都是RabbitMQ对外提供的API中最基本的对象。Connection
是RabbitMQ的socket
链接,它封装了socket
协议相关部分逻辑。ConnectionFactory
为Connection
的制造工厂。
Channel
是我们与RabbitMQ
打交道的最重要的一个接口,我们大部分的业务操作是在Channel
这个接口中完成的,包括定义Queue
、定义Exchange
、绑定Queue
与Exchange
、发布消息等。
Connection
就是建立一个TCP
连接,生产者和消费者的都是通过TCP
的连接到RabbitMQ Server
中的,这个后续会再程序中体现出来。
Channel
虚拟连接,建立在上面TCP
连接的基础上,数据流动都是通过Channel
来进行的。为什么不是直接建立在TCP
的基础上进行数据流动呢?如果建立在TCP
的基础上进行数据流动,建立和关闭TCP
连接有代价。频繁的建立关闭TCP
连接对于系统的性能有很大的影响,而且TCP
的连接数也有限制,这也限制了系统处理高并发的能力。但是,在TCP
连接中建立Channel
是没有上述代价的。
在官网的教程中,描述了如上六类工作队列模式:
- 简单队列模式:最简单的工作队列,其中一个消息生产者,一个消息消费者,一个队列。也称为点对点模式
- 工作(work)模式:一个消息生产者,一个交换器,一个消息队列,多个消费者。同样也称为点对点模式
- 发布/订阅模式:无选择接收消息,一个消息生产者,一个交换器,多个消息队列,多个消费者。称为发布/订阅模式
- 路由模式:在发布/订阅模式的基础上,有选择的接收消息,也就是通过 routing 路由进行匹配条件是否满足接收消息。
- 主题模式:同样是在发布/订阅模式的基础上,根据主题匹配进行筛选是否接收消息,比第四类更灵活。
- RPC模式:与上面其他5种所不同之处,类模式是拥有请求/回复的。也就是有响应的,上面5种都没有。