交换机的责任主要在于路由分发生产者的消息到队列中,一个Exchange可以binding多个Queue,一个Queue可以同多个Exchange进行binding。
前面我们聊过,我们在简单的使用过程中甚至可以不声明交换机,但这并不意味者rabbitmq可以没有exchange工作。我们不申明是因为rabbitmq提供的默认交换机。
默认交换机(default exchange)实际上是一个由rabbitmq预先声明好的没有名字(名字为空字符串)的直连交换机(direct exchange)。 它有一个特殊的属性使得它对于简单应用特别有用处:那就是每个新建队列(queue)都会自动绑定到默认交换机上,绑定的路由键(routing key)名称与队列名称相同。
这里我借用官方的一个说明来说明默认交换机。当我们声明了一个名为search-indexing-online
的队列,rabbitmq会自动将其绑定到默认交换机上,绑定(binding)的路由键名称也是为search-indexing-online
。因此,当携带着名为search-indexing-online
的路由键的消息被发送到默认交换机的时候,此消息会被默认交换机路由至名为search-indexing-online
的队列中。换句话说,默认交换机看起来貌似能够直接将消息投递给队列,尽管技术上并没有做相关的操作。
那么除了默认交换机,还有那些可以使用的交换机吗?
还记得我们上面虚拟主机和用户篇新建的test虚拟主机和test用户,我们登录进去,看看rabbitmq提供给的默认交换机和其他交换机。
有没有发现,我们新建的虚拟环境里面除了有默认交换机还有amq开头的系统交换机,我们这里并不关心系统交换机的用途,我们重点关注有哪几种交换机。
从上图我们可以看出来,有direct /fanout /headers/topic
四种(默认交换机是direct类型),OK,我们接下来聊一聊其他种类的交换机。
直连型交换机(direct exchange):字面意思已经很好理解了,更好的可以理解为交换机和队列通过routingKey
是一一对应(相当于一条直线路径)完全匹配的,这里要重点理解完全匹配,不同topic
的模糊匹配,直连型交换机是精确匹配的,假设我么指定了routingKey
是test
的话,那么直连型交换机只会将routingKey
是test
的投递到队列,而不会投递类似于test的消息(例如 test1)。尽管交换机和队列通过routingKey
是一一对应的,但是它也可以处理多播路由将同一个消息多播路由到同一个routingKey
的多个队列。
这里我们先回顾一下,上面说过的,一个Exchange
可以binding
多个Queue
,一个Queue
可以同多个Exchange
进行binding
。这里我觉得大家要有一个明确的概念,Exchange
和 Queue
是没有从属关系的,它们之间只是通过routingKey
来绑定的关系。然后我们再回到这个案例,我们有一个直连交换机X,它和2个队列之间建立的关联,X和Q1 之间是我们最常配置的直连交换机的用法,但是实际上一个队列可以多个binding和direct直连交换机绑定。例如Q2,这样实际意义上我们不怎么会用,这里主要让大家理解用法。
这里我们还可以用同一个bindingKey
来把多个queue
绑定到同一个exchange
,这个时候我们的直连交换机就相当于一个多播路由的fanout
交换机。
广播交换机(funout exchange) 将消息路由给绑定到它身上的所有队列,而不理会绑定的路由键。如果N个队列绑定到某个广播交换机上,当有消息发送给此广播交换机时,交换机会将消息的拷贝分别发送给这所有的N个队列。广播交换机用来处理消息的广播路由(broadcast routing)。
广播路由器我觉得是最好理解的,因为它无视了routingKey,只要有队列与之关联,它就会将消息的Copy投递到队列。现实开发中,如果我们有需要将消息投递到多个系统可以考虑广播路由。
主题交换机(topic exchanges) 是我们使用的最多最普遍性能最好的交换机,主题交换机通过对消息的路由键和队列到交换机的绑定模式之间的匹配,将消息路由给一个或多个队列。主题交换机经常用来实现各种分发/订阅模式及其变种。主题交换机通常用来实现消息的多播路由(multicast routing)。
我们把消息投递到topic
交换机的时候一般需要指定一系列由点号连接单词的字符串的routingKey
,同时我们在绑定消息队列和交换机的时候也需要指定一系列由点号连接单词的字符串的routingKey
。
当生产者投递了确定routing key
的消息将会被topic
交换机推送给所有能与routing key
匹配的队列。我们这里需要注意它们之间的匹配规则:
● *(星号):可以(只能)匹配一个单词
● #(井号):可以匹配多个单词(或者零个)
这里需要注意的是单词
,而不是字符
,并且它们是通过.
连接。
我们还是一样,看个案例:
*.orange.* 的路由规则只能匹配由3个单词组成,并且中间的单词是orange
*.*.rabbit 的路由规则只能匹配由3个单词组成,并且最后的单词是rabbit
lazy.# 的路由规则没有词数限制,但是要求首单词必须是lazy
下面我们给出几个路由键,大家理解一下它的分发规则:
lazy Q2可以匹配
hardworking.black.turtle 无匹配
lazy.orange.rabbit Q1 Q2都可以匹配,Q2的两个路由规则都匹配了,但是同一条消息只会被推送到Q2上一次
lazy.orange.rabbit.try 只有Q2可以匹配(注意词数限制)
hardworking.orange.rabbit Q1可以匹配
lazy.white.rabbit Q2可以匹配(但是只会匹配lazy.#规则)
Topic
类型的exchange
是很强大的,也很有趣,我们其实可以使用它的变体来实现其它类型的exchange。
● 当一个队列和exchange绑定的routingKey为”#”时,它将会接收所有的消息,此时和fanout类型的exchange很像。
● 当一个队列和exchange绑定的routingKey为不包含”*”和”#”时,这时候就很像direct类型的exchange。
头交换机(headers exchange):有时消息的路由操作会涉及到多个属性,此时使用消息头就比用路由键更容易表达。头交换机使用多个消息属性来代替路由键建立路由规则。通过判断消息头的值能否与指定的绑定相匹配来确立路由规则。(性能不好,几乎不用,我们这里不讨论,大家就知道还有这个东西就好了)。