Exchange概念
Exchange:交互机,根据路由键转发消息到绑定的队列。
自己说说Exchange在RabbitMQ消息中间件中的作用:
服务器发送消息不会直接发送到队列中(Queue),而是直接发送给交换机(Exchange),然后根据确定的规则,RabbitMQ将会决定消息该投递到哪个队列。这些规则称为路由键(routing key),队列通过路由键绑定到交换机上。消息发送到服务器端(broker),消息也有自己的路由键(也可以是空),RabbitMQ也会将消息和消息指定发送的交换机的绑定(binding,就是队列和交互机的根据路由键映射的关系)的路由键进行匹配。如果匹配的话,就会将消息投递到相应的队列。
Exchange的类型主要有四种,分别是
Direct Exchange:将消息中的
Routing key
与该Exchange
关联的所有Binding
中的Routing key
进行比较,如果相等,则发送到该Binding
对应的Queue
中。Topic Exchange:将消息中的
Routing key
与该Exchange
关联的所有Binding
中的Routing key
进行对比,如果匹配上了,则发送到该Binding
对应的Queue
中。Fanout Exchange:直接将消息转发到所有
binding
的对应queue
中,这种exchange
在路由转发的时候,忽略Routing key
。Headers Exchange:将消息中的
headers
与该Exchange
相关联的所有Binging
中的参数进行匹配,如果匹配上了,则发送到该Binding
对应的Queue
中。
查看exchanges属性,在管控台上查看http://192.168.1.131:15672/#/exchanges
相关属性的说明,如果有多个Virtual host,则还会有Virtual host属性。一般默认的Virtual host是"/",我们知道Virtual host可以做最小粒度的权限控制。
- Virtual host:属于哪个Virtual host。
- Name:名字,同一个Virtual host里面的Name不能重复。
- Durability: 是否持久化,Durable:持久化。Transient:不持久化。
- Auto delete:当最后一个绑定(队列或者exchange)被unbind之后,该exchange自动被删除。
- Internal: 是否是内部专用exchange,是的话,就意味着我们不能往该exchange里面发消息。
- Arguments: 参数,是AMQP协议留给AMQP实现做扩展使用的。
alternate_exchange配置的时候,exchange根据路由路由不到对应的队列的时候,这时候消息被路由到指定的alternate_exchange的value值配置的exchange上。(下面的博客会有说明这参数的具体使用)
unbing之后该exchange删除。
命令行查看exchange信息
使用命令查看exchanges列表,默认的Virtual host
[root@mqserver ~]# rabbitmqctl list_exchanges
Listing exchanges
amq.direct direct
direct
amq.match headers
amq.rabbitmq.log topic
amq.topic topic
amq.headers headers
amq.rabbitmq.trace topic
amq.fanout fanout
指定某个Virtual host的exchanges列表,我指定的事默认的Virtual host(/)
[root@mqserver ~]# rabbitmqctl list_exchanges -p /
Listing exchanges
amq.direct direct
direct
amq.match headers
amq.rabbitmq.log topic
amq.topic topic
amq.headers headers
amq.rabbitmq.trace topic
amq.fanout fanout
使用restful api
查看exchanges列表,api的文档地址,(http://192.168.1.131:15672/api/
)
对应着下面的链接,当前管控台的url/api
具体的地址,输入对应的用户名和密码,看到对应用户的exchanges
列表
http://192.168.1.131:15672/api/exchanges
Direct Exchange
将消息中的Routing key
与该Exchange
关联的所有Binding
中的Routing key
进行比较,如果相等,则发送到该Binding
对应的Queue
中。
- 一个
Exchange
可以Binding
一个或多个Queue
。 - 绑定可以指定
Routing key
,Binding
的多个Queue
可以使用相同的Routing key
,也可以使用不同的Routing key
。
创建三个Exchange
,名称分别是login
,logout
,register
三个exchange。
创建几个Queue
,名称分别是PC
,WAP
,APP
,OA
。
指定它们的Binding
关系,
测试:
查看队列中的消息
其他的可自行测试
特别的Exchange
默认的Exchange(名字为空,AMQP default)
- 默认的
Exchange
不能进行Binding
操作 - 任何发送到该
Exchange
的消息都会被转发到Routing key
指定的Queue
中 - 如果
vhost
中不存在Routing key
中指定的队列名,则该消息会被抛弃。
Topic Exchange
将消息中的Routing key
与该Exchange
关联的所有Binding
中的Routing key
进行对比,如果匹配上了,则发送到该Binding
对应的Queue
中。
匹配规则
* 匹配一个单词
# 匹配0个或多个字符
*,# 只能写在.号左右,且不能挨着字符
单词和单词之间需要用.隔开。
列子
- Routing key是user.log.#,因为#是匹配0个或多个字符,所以下面的可以匹配:
user.log
user.log.info
user.log.a
user.log.info.login
- Routing key是user.log.,因为 匹配一个单词,所以
user.log.info 可以匹配
user.log 不能匹配
user.log.info.login 不能匹配,二个单词
- Routing key是#.log.#
可以匹配:
log
user.log
log.info
user.log.info
user.log.info.a
- Routing key是.log.
log 不匹配
user.log 不匹配
log.info 不匹配
user.log.info 匹配,前后各一个单词
user.log.info.a 不匹配
a.user.log.info 不匹配
- Routing key是*.action.#
action 不符合
action.log 不符合
user.action.log 符合
user.action.log.info 符合
user.action 符合
user.log.action 不符合
- Routing key是#.action.*
action 不符合
user.action 不符合
user.action.action 符合
user.action.login 符合
user.action.login.count 不符合
- Routing key是* 表示匹配一个单词
- Routing key是#,或者#.# 表示匹配所有
如果指定了Exchange是Topic类型的,但是相应的Binding
中的Routing key *
,#
都没有,则相等才转发,类似于Direct Exchange
如果Binding
中的Routing key
为#
或者#.#
,则全部转发,类似Fanout Exchange
(下面会讲到)
测试:
建立一个名称为log
的topic
类型的Exchange
新建三个队列q1
,q2
,q3
分别绑定 *
,#
,#.#
自己定义一脚本,便于测试的时候清除所有队列的消息:
cd /u01
vim purge.sh
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/q1/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/q2/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/q3/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/action_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/log2_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/log_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/sys_log_info_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/sys_log_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/user2_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/user_action_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/user_log_debug_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/user_log_info_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/user_log_queue/contents
curl -X DELETE -u zhihao.miao:123456 http://192.168.1.131:15672/api/queues/%2F/user_queue/contents
给脚本授权
chmod 777 purge.sh
执行脚本
sh purge.sh
测试发送Routing key为这些的消息。
user
user.log
user.log.info
user.log.debug
sys
sys.log.debug
特殊情况,定义一队列q4
,exchange
指定binding
为reg
,没有*
或#
,那么当发送的消息route key
为reg
的时候,能够发送到q4
上,此时类似于Direct Exchange
。
总结
topic Exchange
可以实现Direct Exchange
,Fanout Exchange
的效果。
Fanout Exchange
直接将消息转发到所有binding
的对应queue
中,这种exchange
在路由转发的时候,忽略Routing key
。
Fanout Exchange
这种exchange
效率最高,fanout > direct > topic
定义一个Fanout类型的Exchange,绑定了一些队列,发送的时候全部队列都能收到消息,而与其bind或者发送消息指定的Routing key无关。
使用topic Exchange
实现Fanout Exchange
。
topic Exchange
将所有binding
的queue
的routing key
都指定为#
或者#.#
,此时消息也是全部转发。
Headers Exchange
将消息中的headers
与该Exchange
相关联的所有Binging
中的参数进行匹配,如果匹配上了,则发送到该Binding
对应的Queue
中。
匹配规则:
如果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
的参数少,否则匹配不上。
列子:
此时header.debug符合条件,收到消息。
此时还是header.debug符合条件,收到消息。
此时header.debug和header.error都收到消息。
此时header.debug和header.error都收到消息。