四、RabbitMQ Exchange类型
RabbitMQ
整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。可以把消息传递的过程想象成:当你将一个包裹送到邮局,邮局会暂存并最终将邮件通过邮递员送到收件人的手上,RabbitMQ
就好比由邮局、邮箱和邮递员组成的一个系统。从计算机术语层面来说,RabbitMQ
模型更像是一种交换机模型。
RabbitMQ模型
(https://img2018.cnblogs.com/blog/1070782/201811/1070782-20181126114829628-838184144.png)
从图中可以看出RabbitMQ
主要由Exchange
和Queue
两部分组成,然后通过RoutingKey
关联起来,消息投递到Exchange
然后通过Queue
接收存储。
消息队列运转过程
-
生产者将业务方数据进行可能的包装,之后封装成消息,发送(AMQP协议里这个动作对应的命令为
Basic.Publish
)到Broker
中。 -
消费者订阅并接收消息(AMQP协议里这个动作对应的命令为
Basic.Consume
或者Basic.Get
),经过可能的解包处理得到原始的数据,之后再进行业务处理逻辑。这个业务逻辑并不一定需要和接收消息的逻辑使用同一个线程。
消费者进程可以使用一个线程去接收消息,存入到内存中,比如
Java
中的BlockingQueue
。业务处理逻辑使用另一个线程从内存中读取数据,这样可以将应用进一步解耦,提高整个应用的处理效率。
基本概念
在理解Exchange之前,我们先了解RoutingKey、Binging、Queue和Message概念、
-
RoutingKey:
路由键。生产者将消息发给交换器时,一般指定一个
RoutingKey
,用来指定这个消息的路由规则,而这个RoutingKey
需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。在交换器类型和绑定键(BindingKey)固定的情况下,生产者可以在发送消息给交换器时,通过指定
RoutingKey
来决定消息流向哪里。 -
Binding:
Exchange与Exchange、Queue之间的虚拟连接,Binding中可以包含Routing key或参数。
便于理解,个人把Binding的Routing key称为Bindingkey(官方没有这种键,只是个人方便理解而加入)。
RabbitMQ
中通过Binding将交换器与交换器或队列关联起来,在绑定的时候一般会指定一个BindingKey,这样RabbitMQ
就知道如何正确的将消息路由到队列,如图
注意:
-
default Exchange不能进行Binding,也不需要进行绑定
-
除default Exchange之外,其他任何Exchange都需要和Queue进行Binding,否则无法进行消息路由(转发)
-
Binding的时候,可以设置一个或多个参数,其中参数要特别注意参数类型,如果Routing key中指定的参数类型和消息中指定的参数类型不一致(header Exchange)也不能进行消息转发。
-
Direct Exchange,Topic Exchange进行Binding的时候,发送消息时需要指定Routing key
-
Fanout Exchange,Headers Exchange进行Binding的时候,发送消息时可以不指定Routing key。
-
Queue:
队列,保存消息并将它们转发给消费者。
-
Message
消息。服务器和应用程序之间传送的数据,本质上就是一段数据,由Properties和Payload(body)组成。
**Exchange: **交换器。根据路由键转发消息到绑定的队列。
Exchange
在RabbitMQ
中的作用:客户端发送消息不会直接发送到队列(Queue)中,而是直接发送给交换器(Exchange),由交换器将消息路由到一个或多个队列中。
RabbitMQ中,所有生产者提交的消息都由Exchange来接受,然后Exchange按照特定的策略转发到Queue进行存储。
RabbitMQ提供了四种Exchange:fanout,direct,topic,header。但常用的主要是fanout,direct,topic。
性能排序:fanout > direct >> topic。比例大约为11:10:6。
-
direct
把消息路由到与
BindingKey
和RoutingKey
完全相等的队列中。- 一个Exchange可以Binding一个或多个Queue
- 绑定可以指定RoutingKey,Binding的多个Queue可以使用相同的BindingKey,也可以使用不同的BindingKey
如下图,在该类型下指定
RoutingKey
为warming
,Exchange
和Queue1
、Queue2
的BindingKey
都有warming
,所以消息都会路由到Queue1
和Queue2
。如果指定
RoutingKey
为info
,而Exchange
有BindingKey
为info
的只有Queue2
,所以消息只能路由到Queue2
。注意:
默认的Exchange(名字为空,显示为
(AMQP default)
)- 默认的Exchange不能进行Binding操作
- 任何发送到该Exchange的消息都会被转发到Routing key指定的Queue中
- 如果vhost中不存在Routing Key中指定的队列名,则该消息会被抛弃
-
topic
个人把Binding的Routing key称为Bindingkey(官方没有这种键,只是个人方便理解而加入)。
与
direct
类型的交换器路由规则BindingKey
和RoutingKey
完全相等不同,将消息中的Routing key
与该Exchange
关联的BindingKey
进行对比,如果匹配上了,则发送到该Binding
对应的Queue
中。匹配规则
*
匹配一个单词
#
匹配0个或多个字符
*
,#
只能写在.
号左右,且不能挨着字符
单词和单词之间需要.
隔开。例子
-
BindingKey是
user.log.#
,因为#
是匹配0个或多个字符,所以下面RoutingKey的可以匹配:user.log user.log.info user.log.a user.log.info.login
-
BindingKey是
user.log.*
,因为*
匹配一个单词,所以user.log.info 可以匹配 user.log 不能匹配 user.log.info.login 不能匹配,二个单词
-
BindingKey是
#.log.#
, 可以匹配:log user.log log.info user.log.info user.log.info.a
-
BindingKey是
*.log.*
log 不匹配 user.log 不匹配 log.info 不匹配 user.log.info 匹配,前后各一个单词 user.log.info.a 不匹配 a.user.log.info 不匹配
-
BindingKey是
*.action.#
action 不符合 action.log 不符合 user.action.log 符合 user.action.log.info 符合 user.action 符合 user.log.action 不符合
-
BindingKey是
#.action.*
action 不符合 user.action 不符合 user.action.action 符合 user.action.login 符合 user.action.login.count 不符合
-
BindingKey是
*
表示匹配一个单词 -
BindingKey是
#
,或者#.#
表示匹配所有
如果指定了Exchange是Topic类型的,但是相应的
BindingKey
中只有单词,*
和#
都没有,则相等才转发,类似于Direct Exchange
。
如果BindingKey
为#
或者#.#
,则全部转发,类似Fanout Exchange
(下面会讲到)如下图
RoutingKey
为"com.rabbitmq.client"
的消息会同时路由到Queue1
和Queue2
;RoutingKey
为"com.hidden.client"
的消息只会路由到Queue2
中;RoutingKey
为"com.hidden.demo"
的消息只会路由到Queue2
中;RoutingKey
为"java.rabbitmq.demo"
的消息只会路由到Queue1
中;RoutingKey
为"java.util.concurrent"
的消息将会被丢弃或返回给生产者(需要设置mandatory
参数),因为没有匹配任何路由键
-
-
fanout
直接将消息转发到所有
binding
的对应queue
中,这种exchange
在路由转发的时候,忽略Routing key
。Fanout Exchange
这种
exchange效率最高,
fanout > direct > topic定义一个Fanout类型的Exchange,绑定了一些队列,发送的时候全部队列都能收到消息,而与其bind或者发送消息指定的Routing key无关。
-
headers
将消息中的
headers
与该Exchange
相关联的所有Binging
中的参数进行匹配,如果匹配上了,则发送到该Binding
对应的Queue
中。headers
类型的交换器的性能比较差,少用。匹配规则:
如果Binding
中的
x-match = all
:表示所有的键值对都匹配才能转发到消息。
x-match = any
: 表示只要有键值对匹配就能转发消息。注意:
Binging
的时候,至少需要指定两个参数,其中的一个是x-match = all
或x-match = any
。Binging
的时候,不需要指定Routing key
- 发送消息的时候,不需要指定
Routing key
- 转发消息的时候,忽略
Routing key
- 如果是
x-match = all
则发送的headers
不能比bingding
的参数少,否则匹配不上。