跳到主要内容

RabbitMQ 消息发送模式详解

1. 前言

Hello,大家好。今天会为同学们介绍 RabbitMQ 中的消息发送模式。RabbitMQ 作为一款消息队列中间件,其提供的消息发送模式必然是 RabbitMQ 的亮点所在。

理解并掌握 RabbitMQ 中的消息发送模式,是使用 RabbitMQ 进行消息通信的基础,同时也是用好 RabbitMQ 的关键所在,所以,请大家务必掌握本节内容,话不多说,就让我们来看看 RabbitMQ 中都有哪些消息发送模式,以及消息是如何发送的吧。

本节主要内容:

  • 什么是消息发送模式;
  • RabbitMQ 中为我们提供了哪些消息发送模式;
  • RabbitMQ 消息模式详解及注意事项。

希望各位同学可以理解本节内容,而不是死记硬背。

2. 什么是消息发送模式 ?

对于消息发送模式这一名词,我们先抛开 RabbitMQ 不说,单从字面意义上去理解,很容易知道,消息发送模式指的就是:消息发送时,所使用的方法或者中间介质,换成大白话就是说,消息是通过什么媒介去进行发送的。

在 RabbitMQ 中,消息发送模式我们完全可以按照上述所说的来理解,只不过,在 RabbitMQ 中,对消息传输所通过的媒介有专业的术语罢了。

接下来就让我们来看一下,在 RabbitMQ 中都有哪些消息发送模式。

3. RabbitMQ 中为我们提供了哪些消息发送模式 ?

在 RabbitMQ 中,所有经过 RabbitMQ 来传输的消息,都需要经过 RabbitMQ 的队列来进行传输,至于什么是队列,我在前面的文章中已经讲过,这里不再赘述。

在介绍 RabbitMQ 中都有哪些消息发送模式之前,我们需要首先了解,在 RabbitMQ 中的消息发送模式是如何体现的。

消息在 RabbitMQ 队列传输的过程中,根据不同的传输方式,以及所使用的队列种类的不同,一共划分了 5 个消息传输模式,而这 5 个消息传输模式,就是我们所说的消息发送模式。

根据 RabbitMQ 所实现的消息投递方式来划分,可以将消息发送模式分为两大类,分别是点对点模式、发布订阅模式;根据 RabbitMQ 所采用的队列方式以及匹配规则的不同,可以将消息发送模式分为五大类,分别是普通队列模式、工作队列模式、发布订阅模式、直接模式、主题模式。

由于按照消息投递方式所划分的范围较广,我们不能充分了解每个消息发送模式的内容,所以,在介绍消息发送模式时,我会按照 RabbitMQ 所采用的队列方式和匹配规则的不同来进行讲解,请同学们做好准备。

4. RabbitMQ 消息模式详解及注意事项

我们知道,在 RabbitMQ 中,消息的产生是源自生产者,对应的,消费消息是依靠消费者,而在生产者生产消息到消费者最终消费消息的过程中,消息发送模式扮演着重要的角色。

如果需要将消息发送模式结合生产者与消费者进行理解的话,那么,我们可以这样来理解:在生产者生产出一条消息后,需要经过 RabbitMQ 的通道来发送给消费者,消费者接收到消息,并最终对消息进行消费,这其中的通道,指的就是 RabbitMQ 的消息发送模式

接下来让我们具体来看一下,RabbitMQ 是如何把生产者生产的消息传输给消费者消费的。

约定:

由于在本节中所使用的消息发送模式原理图均来自官网,所以图中每个元素都代表什么意思,我在这里一并说过,后面不再赘述:

天蓝色椭圆 + 其中的字母 P : 代表生产者。

蓝色的椭圆 + 其中的字母 C + 数字下表 : 代表消费者。

深蓝色椭圆 + 其中的字母 X : 代表交换机。

交换机上方的 type : 代表交换机的类型。

橙色小矩形块所组成的大矩形块 : 代表具体的一个队列。

图中的箭头,不带字母标识的 : 代表消息的流向。

图中箭头上的字母标识 : 代表特定模式下的 key 值。

4.1 直接模式

定义:

直接模式,即直接发送消息模式,指的是将消息直接发送给消费者。

描述:

直接模式允许将多个队列绑定到一个交换机上,在生产者发送消息给交换机时,需要携带一个 key ,而这个 key 一般被称为 routing key 或者 binding key,所以直接模式有时也被称为路由模式。

Tips: RabbitMQ 一般将这个 key 叫做 binding key,但是在实际情况中,出于字面意思,习惯性地将 key 叫做 routing key

直接模式总共分为两种业务场景,我们先来看第一种业务场景,一般被叫做’单 key 绑定’,如下图所示:

从图中我们可以看到,交换机的 type 被声明成了 direct ,这说明我们使用的交换机是直接交换机,即使用的消息发送模式是直接模式;

orange、black、green 分别表示不同的两个 routing key ,orange 这一个 key 绑定了一个队列,black、green、两个不同的 key 也绑定了一个队列,这种现象就是直接模式的第一种业务场景,单 key 绑定。

单 key 绑定的队列,在生产者生产出消息之后,会根据不同 key 指向的不同队列来将消息进行分发,即使是不同的 key 绑定了同一队列。

我们来看直接模式的最后一个业务场景,多重 key 绑定,如下图所示:

在图中我们可以看到,Q1、Q2 两个队列,分别绑定到了 routing key 均为 black 的 direct 交换机上,即名称相同的一个 key 绑定到了多个队列上面,这种现象被称为多重 key 绑定。

在多重 key 绑定下,生产者生产的消息均会被发送到相同 key 值所绑定的队列上面,这里需要同学们注意。

实现伪代码:

// 生产者
channel.basicPublish(EXCHANGE_NAME, "Routing Key", ...)

// 消费者
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "Routing Key"


代码解释:

第 2 行,我们使用 channel 的 basicPublish 方法来指定第二个参数,即我们的 routing key 的名称。

第 5 行,我们使用 channel 的 queueBind 方式来将消息队列绑定到名为 Routing Key 的直接模式交换机上。

Tips:

  1. 一般,我们在使用 RabbitMQ 时,默认会使用直接模式来发送消息,直接模式也是使用最多的消息发送模式,如果其他消息发送模式不能理解,则务必理解直接模式;
  2. 在使用直接模式时,一定不要忘了指定 routing key ,否则,将不能使用直接模式来发送消息;
  3. 当我们绑定了多个队列到交换机上时,一旦消息被发送,则符合同一 routing key 的队列都会接收到消息。

4.2 发布订阅模式

定义:

发布订阅模式,即生产者发布消息,消费者通过订阅的方式来消费消息。

其实,发布订阅模式在我看来,不过是给传统的发送和接收起一个高大上的名字罢了,本质上仍热是消息的生产和消费,只不过这种模式更像与发布和订阅,因此得名发布订阅模式。

描述:

发布订阅模式只有一种实际的业务场景,我们把他称为群发模式。

上图所示场景也是发布订阅模式中的一种,但是这种模式没有任何存在意义,因为在这种模式下,生产者生产出一条消息之后,将消息直接发送到了交换机上,大家注意看,此时的交换机上没有绑定任何消息队列,所以,此时位于交换机上的消息将丢失,消费者无法拿到消息进行消费。

接下来让我们看看实际上的发布订阅模式:

生产者生产一条消息后,将消息首先发送到交换机上,交换机进行检测,发现存在两个队列都绑定在自身上面,于是,将消息全部投递到所绑定的队列上面,最后再由消费者接收消息并消费。

发布订阅模式的特点,就是一个生产者、一个交换机、多个队列、多个消费者,由于生产者生产出来的消息会发送到绑定在交换机上的所有队列上,这种场景很类似于我们给很多人群发消息,所以,这种模式被叫做群发模式。

实现伪代码:

// 生产者
channel.exchangeDeclare(EXCHANGE_NAME, "fanout")

// 消费者
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "")
channel.basicConsume(QUEUE_NAME, false, consumer)


代码解释:

第 2 行,我们使用 channel 的 exchangeDeclare 方法,将交换机的类型指定为 fanout 交换机,这是使用发布订阅模式的前提。

第 5 行,我们使用 channel 的 queueBind 方法,为交换机绑定一个队列,如果在发布订阅模式下,不绑定消息队列到交换机上,则消息会丢失,消费者接收不到任何消息。

第 6 行,我们使用 channel 的 basicConsume 方法,来接收由消息队列发送的消息并消费。

Tips:
1.由于没有绑定队列到交换机上的这种方式会丢失消息,所以在实际工作中,这个方法几乎从不使用,因为没有任何意义;
2.使用发布订阅模式,在给交换机绑定队列时,不要手动指定队列的 key 值,因为 RabbitMQ 会自动生成相同的 key 值;
3. 发布订阅模式一般用于不用指定特殊的 key 值,且需要消息批量发送的业务场景。

4.3 普通队列模式

定义:

普通队列模式,即最简单的消息发送模式,不使用任何交换机,由生产者、队列、消费者组合完成消息的发送和接收。

描述:

普通队列模式,由于其操作简单,所以又被称为简单模式,如下图所示:

普通队列模式,在生产者生产完消息之后,直接将消息发送到队列中去,不经过交换机进行处理,然后由消费者直接接收消息并消费。在这个过程中间,没有我们需要特别注意的地方。

实现伪代码:

// 生产者
channel.queueDeclare(QUEUE_NAME, false, false, false, null)

// 消费者
channel.basicConsume(QUEUE_NAME, true, consumer)


代码解释:

第 2 行,我们使用 channel 的 queueDeclare 方法来为通过绑定消息队列,并指定消息队列的名称。

第 5 行,我们是使用 channel 的 basicConsume 方法来直接从队列接收消息,并自动监听消费。

Tips:

  1. 普通队列模式操作简单,适合很简单的业务场景,同时,初学者更易于理解。
  2. 由于普通队列模式所能实现的业务场景太过简单,所以在实际业务场景中,很少会用到。

4.4 工作队列模式

定义:

工作队列模式,和普通队列模式有点像,都是不使用任何交换机,由生产者、队列、消费者组合完成消息的发送和接收,只不过工作队列支持存在多个消费者,而普通队列模式只支持一个消费者。

描述:

工作队列模式下,生产者生产出消息后,直接将消息发送到消息队列中,然后多个消费者按照一个随机的顺序来依次接收消息并消费,存在多个消费者消费消息时,下一个消费者只能等待上一个消费者消费结束后才能接收消息并进行消费。

这就提示我们,在实际工作中,我们可以把费时的业务操作交给 RabbitMQ 去做,这样可以提升代码的执行效率。

实现伪代码:

// 生产者
channel.basicPublish(QUEUE_NAME, null, message.getBytes());
Thread.sleep(1000);

// 消费者
Delivery delivery = consumer.nextDelivery();
Thread.sleep(1000);

代码解释:

第 2 行,我们使用 channel 的 basicPublish 方法来生成一条消息。

第 3 行,在生成一条消息之后,我们等待 1000 毫秒,即 1 秒后再次生成一条消息。

第 5 行,我们使用 consumer 的 nextDelivery 方法来依次获取生产者生产的消息。

第 6 行,在消费完一条消息之后,我们让下一个消费者等待 1 秒钟,再去消费下一条消息。

Tips:
1.工作队列模式与发布订阅模式有相同之处,既他们都是经过一个队列来向多个消费者发送消息,不同之处在于,前者不用绑定交换机,而后者则需要使用交换机;

2.应用工作队列模式,一定要根据实际业务需求和实际业务场景,设置好多个消费者间等待消费消息的时间,如果这个间隔时间设置太久,则容易造成下一个消费者持续等待,严重占用CPU资源,如果设置时间太短,则业务逻辑还没执行完成就开始了下一个消息的消费,这两种业务场景都是不应该出现的

4.5 主题模式

定义:

主题模式,也被称为通配符模式,官网一般称为主题模式,即交换机与消息队列所绑定的 key 值可以像匹配通配符的方式,来匹配消息队列,到底什么意思呢,我们往下看。

描述:

主题模式对 routing key 的匹配规则做了改进,上述其他四种模式中有涉及 key 匹配的地方都是完全匹配,即名称必须相等时才能把 key 匹配上,而对于主题模式,则不需要这样。

主题模式将 key 值中的每个单词或者关键词,使用英文状态下的 . 符号进行间隔,如上图所示。上图中为我们列举了主题模式中支持的所有通配符语法,我们一个一个来介绍:

Tips: 由于 * 号是 MD 语法关键字,所以这里暂时用 ^ 号代替,同学们注意。

.orange. : 表示在 orange 的两侧可以匹配一个 key 值,例如 123.orange.456 、abc.orange.456 等,但是,abc.orange.456.123 这个是不可以的。

..rabbit : 用法和上述 orange 相同,例如: 123.abc.rabbit 、abd.acd.rabbit 等。

lazy.# : 表示在 lazy 的右侧,可以匹配多个 key 值可以进行通配符匹配,例如:lazy.abc.123 等。

实现伪代码:

// 生产者
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
channel.basicPublish(EXCHANGE_NAME, "key.123", ...);

// 消费者
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "key.\*");

代码解释:

第 2 行,我们使用 channel 的 exchangeDeclare 方法,将交换机声明为 topic 类型,这是使用主题模式的必须项。

第 3 行,我们使用 channel 的 basicPublish 方法来将消息绑定到交换机上。

第 6 行,我们使用 channel 的 queueBind 方法,将消息队列绑定到交换机上,并且设置 key 的匹配策略为 key.*

Tips:

  1. 使用主题模式一定要很清楚每个通配符所代表的意思,以防用错通配符,引起不必要的错误;
  2. 主题模式为我们提供了类似于模糊搜索的功能,当我们不知道如何设置 key 时,我们可以采用主题模式,同时,主题模式为我们 key 的分组也提供了很好地实现方案。
  3. 使用主题模式时,注意 key 值的命名不要太长,也不要太短。

5. 小结

本小节从什么是消息发送模式开始,详细介绍了 RabbitMQ 中的 5 种消息发送模式,对于每一种消息发送模式,采用文字+伪代码+图片的方式进行了全方位的讲解,旨在帮助同学们,通过对本节内容的学习,可以充分了解 RabbitMQ 中都有哪些消息发送模式,以及每种消息发送模式的特点、消息发送原理等。

本小节是用好 RabbitMQ 的基础,在学习本节内容时,一定要理清楚 5 中消息发送模式间的区别与联系,我们只有在充分了解了 RabbitMQ 中的消息发送模式之后,才能很清楚的知道,什么业务场景哪种消息模式最合适,最后,希望同学们学的开心、码的快乐。