所有分类
  • 所有分类
  • 未分类

RabbitMQ的交换器类型与队列模式

简介

本文介绍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。

  1. 若在发送消息的时候设置路由键为“ab”,则消息会路由到Queue1和Queue2。
  2. 若在发送消息的时候设置路由键为“cd”,则消息会路由到Queue2。
  3. 若在发送消息的时候设置路由键为“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交换器。
  1. 一个队列,一条消息只会被一个消费者消费(有多个消费者的情况也是一样的)。
  2. 订阅模式,路由模式,主题模式,他们的相同点就是都使用了交换机,只不过在发送消息给队列时,添加了不同的路由规则。订阅模式没有路由规则,路由模式为完全匹配规则,主题模式有正则表达式,完全匹配规则。
  3. 在订阅模式中可以看到一条消息被多个消费者消费了,不违背第一条总结,因为一条消息被发送到了多个队列中去了。
  4. 在交换机模式下:队列和路由规则有关
  5. 在有交换机的模式下:生产者只用关心交换机与路由规则即可,无需关心队列
  6. 消费者不管在什么模式下:永远不用关心交换机和路由规则,消费者永远只关心队列,消费者直接和队列交互

简单模式

一个生产者对应一个消费者。

work模式

一个生产者对应多个消费者,但是只能有一个消费者获得消息。

发布/订阅 模式

一个消费者将消息首先发送到交换器,交换器绑定到多个队列,然后被监听该队列的消费者所接收并消费。

路由模式

生产者将消息发送到direct交换器,在绑定队列和交换器的时候有一个路由key,生产者发送的消息会指定一个路由key,那么消息只会发送到相应key相同的队列,接着监听该队列的消费者消费消息。也就是让消费者有选择性的接收消息。

主题模式

根据路由key进行完整的匹配(完全相等才发送消息),这里的通配符模式通俗的来讲就是模糊匹配。符号“#”表示匹配一个或多个词,符号“*”表示匹配一个词。

[/vip]

0

评论2

请先

  1. fanout的图和direct是一样的,是不是错的?
    小楊同学 2024-02-27 0
    • 不一样的:exchange的type不一样。可以再仔细看下
      自学精灵 2024-02-27 0
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录