跳到主要内容

RabbitMQ 交换机详解

1. 前言

Hello,大家好。本小节为大家介绍 RabbitMQ 中交换机的相关概念,以及交换机的构成及作用。在 RabbitMQ 消息发送原理概述小节中,我们已经对 RabbitMQ 整体架构有了一个初步的了解,已经知道了交换机在 RabbitMQ 中充当的角色,那么本节会继续深入讲解 RabbitMQ 中的交换机。

本节主要内容:

  • 什么是交换机;
  • RabbitMQ 常用交换机详解;

2. 什么是交换机 ?

在 RabbitMQ 中,交换机主要用来将生产者生产出来的消息,传送到对应的频道中,即交换机是一个消息传送的媒介,其英文被称为 exchange 。交换机在 RabbitMQ 中起着承上启下的作用。

RabbitMQ 根据不同业务场景,为我们内置了多种交换机,但是这些交换机并不是每一种都会用到,常用的交换机也就 3 种,接下来让我们看一下都有哪三种吧。

交换机名称类型使用频率
直通交换机Direct
扇形交换机Fanout
主题交换机Topic

3. RabbitMQ 常用交换机详解

3.1 直通交换机

定义:

直通交换机,又被叫做直连交换机,即 Direct Exchange ,是可以直接将消息根据特定匹配规则发送到对应的消息队列的交换机,如果匹配规则相同,则一条消息可以被发送到多个对应的消息队列上,而这个匹配规则是通过 routing_key 来进行匹配。

伪代码:

// 省略与 RabbitMQ 服务端建立连接的过程
String queueName = "test\_direct\_x";
channel.exchangeDeclare("direct\_exchange", "direct");
channel.queueDeclare(queueName, true, false, false, null);

代码解释:

第 2 行,我们声明了一个名为 test_direct_x 队列名称,对于直通交换机而言,这个名称就是我们所说的 routing_key 。

第 3 行,我们使用了 channel 的 exchangeDeclare 方法来声明了一个交换机,其中,该方法的第一个参数表示交换机的名称,第二个参数则表示交换机的类型,这里我们将类型定义为了直连交换机类型,其类型名称为 direct 。

第 4 行,我们使用了 channel 的 queueDeclare 方法来声明了一个队列,其中,该方法的第一个参数为我们声明的 test_direct_x 队列。

消息发送流程:

结合上述代码,直通交换机的消息发送流程如下图所示:

消息在经过 direct_exchange 交换机之后,会根据名为 test_direct_x 的 routing_key 与相应的消息队列进行匹配,如果消息队列 1 、消息队列 2 、消息队列 3 都与该 routing_key 相匹配,那么我们的消息会全部流转到这三个消息队列中去。

3.2 扇形交换机

定义:

扇形交换机,即 Fanout Exchange ,是通过类似广播的形式,将消息传递到消息队列中去,与直通交换机不同的是,扇形交换机不需要绑定 routing_key ,会将消息传递到所有与该交换机绑定的消息队列中去。

伪代码:

// 省略与 RabbitMQ 服务端建立连接的过程
String queueName = "test\_fanout\_x";
channel.exchangeDeclare("fanout\_exchange", "fanout");
channel.queueBind(queueName, "fanout\_exchange", "");

代码解释:

第 2 行,我们声明了一个名为 test_fanout_x 队列。

第 3 行,我们使用了 channel 的 exchangeDeclare 方法来声明了一个交换机,其中,该方法的第一个参数表示交换机的名称,第二个参数则表示交换机的类型,这里我们将类型定义为了扇形交换机类型,其类型名称为 fanout 。

第 4 行,我们使用了 channel 的 queueBind 方法来将交换机与消息队列进行绑定,其中,该方法的第一个参数为我们声明的 test_fanout_x 队列,第二个参数为要绑定的交换机的名称,这里为 fanout_exchange ,对于扇形交换机来说,队列和交换机的绑定是必须的,否则无法传递消息。

消息发送流程:

结合上述代码,扇形交换机的消息发送流程如下图所示:

消息在经过 fanout_exchange 交换机之后,会首先检测有没有已经与该交换机进行绑定的消息队列,如果没有与该交换机进行绑定的消息队列,则消息会自动失效,且跑抛出异常;如果有与该交换进行绑定的消息队列,则 fanout_exchange 交换机会将消息以广播的形式传递到所有的消息队列中去。

上图中,消息队列 1 、消息队列 2 、消息队列 3 这三个消息队列的名称均为 test_fanout_x ,且均与名为 fanout_exchange 的交换机进行了绑定,所以,消息在经 fanout_exchange 交换机之后,均会被传递到这三个队列中去。

3.3 主题交换机

定义:

主题交换机,即 Topic Exchange ,是通过 routing_key 与 bidding_key 的匹配规则进行消息传递的一种交换机。

与直通交换机不同的是,直通交换机中的 routing_key 和 bidding_key 的名称必须保持一致,但是在主题交换机中,bidding_key 会通过一定的规则去匹配 routing_key ,以此将消息发送到相匹配的消息队列中去。

Tips: 交换机与队列之间进行绑定的 key ,被称为 bidding_key ,消息与交换机之间进行绑定的 key ,被称为 routing_key 。

伪代码:

// 省略与 RabbitMQ 服务端建立连接的过程
String queueName = "test.topic.x";
channel.exchangeDeclare("topic\_exchange", "topic");
channel.queueBind(queueName, "fanout\_exchange", "test.#");

代码解释:

第 2 行,我们声明了一个名为 test.topic.x 的队列。

第 3 行,我们使用了 channel 的 exchangeDeclare 方法来声明了一个交换机,其中,该方法的第一个参数表示交换机的名称,第二个参数则表示交换机的类型,这里我们将类型定义为了扇形交换机类型,其类型名称为 topic 。

第 4 行,我们使用了 channel 的 queueBind 方法来将交换机与消息队列进行绑定,其中,该方法的第一个参数为我们声明的 test_fanout_x 队列,第二个参数为要绑定的交换机的名称,这里为 fanout_exchange ,第三个参数为 bidding_key , 这里是 test.# 。

消息发送流程:

结合上述代码,主题交换机的消息发送流程如下图所示:

消息在经过 topic_exchange 交换机之后,会根据 routing_key 与 bidding_key 的匹配规则检索相匹配的消息队列,如果没有检测到任何相匹配的消息队列,则消息会自动失效;如果检测到存在相匹配的消息队列,则消息均会会被传送到这些消息队列中去。

上图中,消息队列 1 、消息队列 2 是我们代码所设置的,bidding_key 为 test.# 的两个消息队列,第三个消息队列的 bidding_key 为 #.topic ,根据主题交换机 # 号匹配规则,routing_key 都会与这些 bidding_key 相匹配,消息均会被传递到这三个消息队列中去。

Tips: 在主题交换机中,除了 # 号匹配规则之外,还有 . 号匹配规则,他们两个的匹配规则大同小异,这里只对 # 好匹配规则做了介绍,希望同学们在课下可以自行了解 . 号的匹配规则。

4. 小结

本小节对常用的 3 种 RabbitMQ 中的交换机进行了详细介绍,从不同种类交换机的概念开始,到交换机的伪代码实现,再到不同种交换机的消息发送流程结束,为各位同学详细介绍了直通交换机、扇形交换机、主题交换机的相关概念,以及消息发送流程,旨在帮助同学们可以对 RabbitMQ 中常用的 3 种交换机都有一个系统性地了解。