简介
本文介绍RabbitMQ的交换器类型和队列模式。
本内容也是Java后端面试常见的问题。
RoutingKey与BindingKey
RoutingKey
RoutingKey:路由键。生产者将消息发给交换器的时候,一般会指定一个RoutingKey用来指明这个消息的路由规则,这个RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。
在交换器类型和绑定键(BindingKey)固定的情况下,生产者可以在发送消息给交换器时,通过指定RoutingKey来决定消息流向哪里。
BindingKey
Binding:绑定。RabbitMQ中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键(BindingKey),这样RabbitMQ就知道如何正确地将消息路由到队列了。
BindingKey并不是在所有的情况下都生效,它依赖于交换器类型,比如fanout类型的交换器就会无视BindingKey,而是将消息路由到所有绑定到该交换器的队列中。
BindingKey其实也属于路由键中的一种,官方解释为:the routing key to use fot the binding。可以翻译为:在绑定的时候使用的路由键。大多数时候,包括官方文档和RabbitMQ Java API中都把BindingKey和RoutingKey看作RoutingKey,为了避免混淆,可以这么理解:
- 在使用绑定的时候,其中需要的路由键是BindingKey。
- 涉及的客户端方法为:channel.exchangeBind、channel.queueBind
- 对应的AMQP命令为:Exchange.Bind、Queue.Bind。
- 在发送消息的时候,其中需要的路由键是RoutingKey。
- 涉及的客户端方法为:channel.basicPublish
- 对应的AMQP命令为:Basic.Publish。
大多数情况下习惯性地将BindingKey写成RoutingKey,尤其是在使用direct类型的交换器的时候。
交换器类型
交换器分为四种,分别是:direct、fanout、topic 和 headers。AMQP协议里还提到另外两种类型:System和自定义,这里不予描述。
前面三种对应的队列模式分别是:路由模式、发布订阅模式和通配符模式。
headers 交换器允许匹配 AMQP 消息的 header 而非路由键,除此之外,header 交换器和 direct 交换器完全一致,但是性能却差很多,因此基本上不会用到该交换器,这里也不详细介绍。
direct
如果路由键完全匹配的话,消息才会被投放到相应的队列。
以上图为例,交换器的类型为direct。
- 若在发送消息的时候设置路由键为“ab”,则消息会路由到Queue1和Queue2。
- 若在发送消息的时候设置路由键为“cd”,则消息会路由到Queue2。
- 若在发送消息的时候设置路由键为“def”,则消息会路由到Queue2。
对应的示例代码如下:
channel.basicPublish(EXCHANGE_NAME,"ab", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
fanout
当发送一条消息到fanout交换器上时,它会把消息投放到关联到此交换器上的所有队列。
以上图为例,交换器的类型为fanout。
在发送消息的时候无论设置路由键为什么,消息都会路由到Queue1和Queue2。就算是设置了Binding Key,fanout会忽视掉。
topic
设置模糊的匹配方式。它规定:
- RoutingKey
- 为一个点号“.”分隔的字符串(被点号“.”分隔开的每一段独立的字符串称为一个单词),如“ab.cd.efg”、“aa.bb.ccc”。
- BindingKey
- BindingKey和RoutingKey—样也是点号“.”分隔的字符串;
- BindingKey中可以存在两种特殊字符串“*”和“#”,用于做模糊匹配。
- “*”:匹配一个单词
- “#”:用于匹配多个单词(可以是零个)
以上图为例,交换器的类型为topic。下边写出不同的路由键的消息会被路由到的队列。
- “product.xiaomi.phone”:同时路由到Queue1和Queue2
- “department.huawei.it”:只路由到Queue2;
- “department.xiaomi.hr”:只路由到Queue1;
- “department.huawei.hr”:消息被丢弃或返回给生产者(需设置mandatory参数),因为它不匹配任何路由键。
已有的交换器
在RabbitMQ默认定义一些交换机,主要如下:
1. 空字符串的Direct Exchange
默认交换机(default exchange)实际上是一个由RabbitMQ预先声明好的名字为空字符串的直连交换机(direct exchange)。它有一个特殊的属性使得它对于简单应用特别有用处:那就是每个新建队列(queue)都会自动绑定到默认交换机上,绑定的路由键(routing key)名称与队列名称相同。
如:当你声明了一个名为”hello”的队列,RabbitMQ会自动将其绑定到默认交换机上,绑定(binding)的路由键名称也是为”hello”。因此,当携带着名为”hello”的路由键的消息被发送到默认交换机的时候,此消息会被默认交换机路由至名为”hello”的队列中。即默认交换机看起来貌似能够直接将消息投递给队列,如同我们之前文章里看到一例子。
2. amq.*的名称的交换机
这些是RabbitMQ默认创建的交换机。这些队列名称被预留做RabbitMQ内部使用,不能被应用使用,否则抛出403 (ACCESS_REFUSED)错误
队列模式
简介
模式 | 说明 |
简单模式 | 一个生产者对应一个消费者。无需交换器,只需队列。 |
work模式 | 一个生产者对应多个消费者,但是只能有一个消费者获得消息。无需交换器,只需队列。 |
发布/订阅模式 | 一个消费者将消息首先发送到交换器,交换器绑定到多个队列,然后被监听该队列的消费者所接收并消费。 对应fanout交换器。 |
路由模式 | 生产者将消息发送到direct交换器,在绑定队列和交换器的时候有一个路由key,生产者发送的消息会指定一个路由key,那么消息只会发送到相应key相同的队列,接着监听该队列的消费者消费消息。也就是让消费者有选择性的接收消息。 对应direct交换器。 |
主题模式 | 生产者将消息发送到direct交换器,根据路由key进行完整的匹配(完全相等才发送消息),这里的通配符模式通俗的来讲就是模糊匹配。 符号“#”表示匹配一个或多个词,符号“*”表示匹配一个词。 对应topic交换器。 |
- 一个队列,一条消息只会被一个消费者消费(有多个消费者的情况也是一样的)。
- 订阅模式,路由模式,主题模式,他们的相同点就是都使用了交换机,只不过在发送消息给队列时,添加了不同的路由规则。订阅模式没有路由规则,路由模式为完全匹配规则,主题模式有正则表达式,完全匹配规则。
- 在订阅模式中可以看到一条消息被多个消费者消费了,不违背第一条总结,因为一条消息被发送到了多个队列中去了。
- 在交换机模式下:队列和路由规则有关
- 在有交换机的模式下:生产者只用关心交换机与路由规则即可,无需关心队列
- 消费者不管在什么模式下:永远不用关心交换机和路由规则,消费者永远只关心队列,消费者直接和队列交互
简单模式
一个生产者对应一个消费者。
work模式
一个生产者对应多个消费者,但是只能有一个消费者获得消息。
发布/订阅 模式
一个消费者将消息首先发送到交换器,交换器绑定到多个队列,然后被监听该队列的消费者所接收并消费。
路由模式
生产者将消息发送到direct交换器,在绑定队列和交换器的时候有一个路由key,生产者发送的消息会指定一个路由key,那么消息只会发送到相应key相同的队列,接着监听该队列的消费者消费消息。也就是让消费者有选择性的接收消息。
主题模式
根据路由key进行完整的匹配(完全相等才发送消息),这里的通配符模式通俗的来讲就是模糊匹配。符号“#”表示匹配一个或多个词,符号“*”表示匹配一个词。
[/vip]
请先
!