分享

RabbitMQ 入门教程(二)

 夜猫速读 2022-05-05 发布于湖北

RabbitMQ 基础核心配置文件介绍

1. 前言

Hello,大家好。今天会为同学们介绍 RabbitMQ 中的基础核心配置文件。这些基础核心配置文件是保证我们的 RabbitMQ 服务正常运行的基础,如果我们没有根据实际情况去配置这些文件,那么我们的 RabbitMQ 服务可能就不会按照我们计划的那样去运行,也就不能达到我们预期的结果。

理解并掌握 RabbitMQ 基础核心配置文件的配置方法,以及基础核心配置属性,是灵活配置和应用 RabbitMQ 服务的前提,我们只有掌握了 RabbitMQ 的配置手段之后,我们才能在不同场景去应用 RabbitMQ 。

本节主要内容:

  • RabbitMQ 环境相关配置文件及参数;

  • RabbitMQ 基础配置文件及参数;

  • RabbitMQ 额外配置文件及参数。

2. RabbitMQ 环境相关配置文件及参数

2.1 文件定义与路径

RabbitMQ 的环境配置文件,主要是用来对 RabbitMQ 服务所运行的环境进行配置,该配置文件根据所处的平台设置了不同的文件名称,在 Windows 平台中,该配置文件被称为 rabbitmq-env-conf.bat ,在 Centos 平台中,该配置文件被称为 rabbitmq-env.conf 。

如果同学们在安装 RabbitMQ 服务时,均采用了默认安装的方式,那么在 Windows 平台中,rabbitmq-env-conf.bat 配置文件的所在目录就位于 RabbitMQ 服务的安装目录下的 sbin 目录中;在 Centos 平台中,rabbitmq-env.conf 配置文件的所在目录就位于 /usr/lib/rabbitmq/bin 目录下。 如果大家在安装 RabbitMQ 服务时,采用了自定义安装的方式,那么请到各自对应的目录下去寻找该配置文件。

Tips: 本着简洁明了的原则,本节所介绍的 RabbitMQ 配置文件均以 Centos 平台下的为例,这和 Windows 平台大同小异,并没有其他的特殊之处。

2.2 核心配置属性介绍

RABBITMQ_NODE_IP_ADDRESS 属性

RABBITMQ_NODE_IP_ADDRESS 属性是用来描述可访问 RabbitMQ 服务的主机地址,具体到我们的工作当中,就是允许哪些应用程序访问我们的 RabbitMQ 服务。

该属性默认值为空字符串,表示任何应用程序都可以访问我们的 RabbitMQ 服务。那么,如果我们只允许一个应用程序来访问我们的 RabbitMQ 服务,我们应该怎么来配置呢?如下代码所示:

// 假定我们的应用程序所在地址为 192.165.22.123
RABBITMQ_NODE_IP_ADDRESS="192.165.22.123"
代码块12

通过上述代码,我们可以知道,如果我们想指定应用程序访问我们的 RabbitMQ 服务,那么我们只需要将我们应用程序所在地址作为字符串的形式,来发赋给 RABBITMQ_NODE_IP_ADDRESS 属性即可。

RABBITMQ_NODE_PORT 属性

RABBITMQ_NODE_PORT 属性是用来描述 RabbitMQ 服务所使用的网络端口,即 RabbitMQ 服务在服务器上所绑定的服务端口。

该属性默认值为 5672 ,即 RabbitMQ 服务默认使用 5672 端口。如果我们想改变 RabbitMQ 服务所绑定的端口,我们只需要按照上述属性的设置步骤即可,如下代码所示:

// 假定我们需要将 RabbitMQ 的服务绑定到 6672 端口上
RABBITMQ_NODE_PORT="6672"
代码块12

RABBITMQ_NODENAME 属性

RABBITMQ_NODENAME 属性是用来描述 RabbitMQ 服务当前所在节点的名称。

该属性的默认值是根据不同操作系统来定义的,在 Windows 系统中,RABBITMQ_NODENAME 属性的默认值为 rabbit@%COMPUTERNAME% ,即我们电脑的名称;在 Centos 系统中,RABBITMQ_NODENAME 属性的默认值为 rabbit@$HOSTNAME ,即我们主机的名称。

同样地,如果我们想自定义 RabbitMQ 服务的节点名称,我们可以这样来做:

// 假定我们需要将当前 RabbitMQ 服务所在节点的名称修改为 rabbitmq-server-one
RABBITMQ_NODENAME="rabbitmq-server-one"
代码块12

Tips: 一般来说,如果我们的 RabbitMQ 服务只有一个节点,是不会修改 RabbitMQ 的服务名称的,如果我们的 RabbitMQ 服务存在多个节点,即 2个及 2 个以上节点时,我们需要根据每个 RabbitMQ 所起到的服务来为不同的 RabbitMQ 节点设置服务名称。

RABBITMQ_USE_LONGNAME 属性

RABBITMQ_USE_LONGNAME 属性是是否启用 RabbitMQ 全量名称的开关,当我们开启后,我们每个 RabbitMQ 节点的名称以及其他可命名的地方都会采用完整名称规则的方式来进行命名。

该属性的默认值为 false ,即不使用 RabbitMQ 全量名称规则来命名,只是用默认的正常规则来进行命名,如果我们需要打开 RabbitMQ 全量命名,我们可以这样打开:

RABBITMQ_USE_LONGNAME=true
代码块1

Tips: 在实际工作中,很少会使用 RabbitMQ 的全量命名规则,因为这种命名策略生成的名称非常长,且不易读,不利于我们对 RabbitMQ 服务节点的维护,当然,如果我们必须要使用这种命名规则,也是无可厚非的。

RABBITMQ_SERVICENAME 属性

RABBITMQ_SERVICENAME 属性用来描述 RabbitMQ 服务的服务名称。

该属性只对 Windows 系统起作用,其默认值为 RabbitMQ ,在 Centos 系统中,RabbitMQ 的服务名称不可修改,统一被命名为 rabbitmq-server.service 。

那么,在 Windows 系统中,如果我们想修改 RabbitMQ 的服务名称,我们只需要找到 services.msc 文件,并以文本文档的类型打开它,在里面找到 RABBITMQ_SERVICENAME 属性,将它的值修改成我们想要的名称即可,如下代码所示:

// 假定我们需要修改服务名称为 rabbitmq-server
RABBITMQ_SERVICENAME="rabbitmq-server"
代码块12

RABBITMQ_CONSOLE_LOG 属性

RABBITMQ_CONSOLE_LOG 属性用来规定 RabbitMQ 服务所生成的服务日志的路径,如果没有设置该属性,则 RabbitMQ 不会生成任何服务日志。

该属性的默认值为空,即默认没有规定 RabbitMQ 服务日志的生成位置。

如果我们想指定 RabbitMQ 服务所生成的位置,我们只需要将路径赋值给 RABBITMQ_CONSOLE_LOG 属性即可,如下代码所示:

RABBITMQ_CONSOLE_LOG=/usr/temp/rabbtmq-log/one.log
代码块1

RABBITMQ_DIST_PORT 属性

RABBITMQ_DIST_PORT 属性用来描述 RabbitMQ 服务节点间进行通信的端口号。

该属性的默认值为 RABBITMQ_NODE_PORT + 20000 。

修改方式如下代码所示:

// 假定我们需要修改端口号为 RABBITMQ_NODE_PORT + 20001
RABBITMQ_DIST_PORT=RABBITMQ_NODE_PORT + 20001
代码块12

Tips: 1. 在实际工作中,一般不会刻意去修改 RabbitMQ 服务节点间进行通信的端口号,除非我们的应用程序所绑定的端口与该端口发生了冲突。\2. 修改 RabbitMQ 服务节点间通信端口号我们可以采用一种自增的原则,即我们不要修改 RABBITMQ_NODE_PORT ,我们修改的是后面的 20000 ,将 20000 进行一次累加即可。3.rabbitmq-env.conf 文件中的所有属性在发生变化之后,都需要重启我们的 RabbitMQ 服务才能生效。

3. RabbitMQ 基础配置文件及参数

3.1 文件定义与路径

RabbitMQ 基础配置文件主要用来对 RabbitMQ 服务本身做一些配置,从而来满足我们的业务需求。同样地,该配置文件也是根据不同的操作系统来进行命名的,在 Windows 系统中,该配置文件被称为 rabbitmq-conf.bat , 在 Centos 系统中,该配置文件被称为 rabbitmq.conf 。

在 Centos 系统中,该配置文件默认的路径为 /etc/rabbitmq/ ,在 Windows 系统中,该配置文件默认的路径为 %APPDATA%\RabbitMQ ,其中,APPDATA 指的是 RabbitMQ 中数据文件所在的路径。

3.2 核心配置属性介绍

listeners 属性

listeners 属性是 AMQP 协议用来监听 tcp 端口的监听器,完整属性名称为 listeners.tcp.default 。

该属性的默认值为 5672 ,即 AMQP 协议默认监听 5672 端口。

修改方式同上,这里不再赘述。

log.file.level 属性

log.file.level 属性用来定义 RabbitMQ 服务日志的打印级别,一共有 4 种日志打印级别,分别是 error 、warning 、info 、debug,这四种日志级别根据这个顺序互相包含,即 debug 级别的日志会打印出 error 、warning、info、debug 的所有数据。

该属性默认值为 info ,即默认的服务日志打印级别为 info 级别,会打印包括 error 、warning 、info 的所有数据。

修改方式同上,这里不再赘述。

channel_max & channel_operation_timeout 属性

channel_max 属性是用来规定具体的一个频道与客户端的最大连接数量,该数量的默认值为 2047 。

channel_operation_timeout 属性是用来规定获取具体的一个频道连接的最大超时时间,该时间默认值为 15000 毫秒。

修改方式同上,这里不再赘述。

max_message_size & heartbeat & default_vhost 属性

max_message_size 属性用来规定一条消息的最大占用空间,该属性的单位为比特,默认值为 134217728 ,最大值为 536870912 。

heartbeat 属性用来规定 RabbitMQ 服务中心跳检测的超时时间,如果该属性的值设置为 0 ,则 RabbitMQ 服务的心跳检测机制会自动关闭,该属性的默认值为 60 秒。

default_vhost 属性用来规定 RabbitMQ 服务中默认的虚拟主机名称,默认值为 / 。

修改方式同上,这里不再赘述。

default_user & default_pass & default_user_tags & default_permissions 属性

default_user 属性和 default_pass 属性分别用来规定 RabbitMQ 服务中默认的用户名和密码,默认值均为 guest 。

default_user_tags 属性用来对用户的角色进行设置,默认值为 administrator,即默认用户为 RabbitMQ 服务的超级管理员,如下代码所示:

default_user_tags.administrator = true
代码块1

default_permissions 属性用来规定用户的默认权限,默认值为所有用户都可以对 RabbitMQ 进行配置,以及读写操作。

如果我们想修改用户的权限,那么我们需要这样进行修改:

default_permissions.configure = .*
default_permissions.read = .*
default_permissions.write = .*
代码块123

上述代码中,configure 用来设置是否允许用户对 RabbitMQ 进行配置,read 用来设置用户的读权限,write 用来设置用户的写权限。

cluster_formation.classic_config.nodes 属性

cluster_formation.classic_config.nodes 属性用来设置不同 RabbitMQ 服务节点间连接,该属性会作为一个列表生效,即该列表中的所有 RabbitMQ 服务节点在 RabbitMQ 服务启动时都将被启动,且各节点间的通信通道将被打开。

那么该如何定义我们所需要的节点呢?如下代码所示:

// 假定我们有两个服务节点需要通信
cluster_formation.classic_config.nodes.1 = rabbit@hostname1
cluster_formation.classic_config.nodes.2 = rabbit@hostname2
代码块123

Tips: 1. rabbitmq.conf 文件中的所有属性,一经修改,需要重启 RabbitMQ 服务才可生效。\2. 出于不同的安装方式,rabbitmq.conf 配置文件可能有的安装方式不会自动生成,如果需要,我们可以在上述指定目录新建一个 rabbitmq.conf 文件,并重启 RabbitMQ 服务。

4. RabbitMQ 额外配置文件

文件介绍

通过对上述 RabbitMQ 环境配置文件以及 RabbitMQ 基础配置文件及其中的核心属性的介绍,我们已经将 RabbitMQ 中的所有核心配置项全部介绍完毕了,这些核心配置项基本可以满足我们自定义 RabbitMQ 98% 的需求的需要。

RabbitMQ 额外配置文件是对上述 RabbitMQ 基础配置文件的补充,当我们对这个额外配置文件做了自定义配置之后,那么我们所配置的内容会和 RabbitMQ 基础配置文件相合并,但是这个额外配置文件是通过 erlang 语言的语法来配置的,如果我们想自定义该配置文件的话,还需要我们对 erlang 语言有所了解。

出于本套课程的初衷考虑,本节不会对 RabbitMQ 额外配置文件做进一步的介绍,我们只需要了解 RabbitMQ 配置文件中存在这么一个额外的配置文件即可,这个配置文件在实际工作中几乎是不使用的。

RabbitMQ 额外配置文件只存在于 Centos 系统中,文件名称默认为 advanced.config 。在 Centos 系统中,该文件位于 /etc/rabbitmq 路径下;在 Windows 系统中,该文件位于 %APPDATA%\RabbitMQ 路径下,其中,APPDATA 指的是 RabbitMQ 中数据文件的所在位置。

5. 小结

本小节主要对 RabbitMQ 中的配置文件,及其配置文件属性做了详细介绍。针对基础核心配置文件,例如,RabbitMQ 环境配置文件和 RabbitMQ 基础配置文件,对这些配置文件中的各个核心配置属性都做了详细介绍,对于不需要各位同学掌握的 RabbitMQ 额外配置文件 advanced.config ,各位同学只需要知道它的作用即可。

RabbitMQ 消息发送原理概述

1. 前言

Hello,大家好。今天会为同学们介绍 RabbitMQ 的消息发送原理,RabbitMQ 消息发送原理展开来说有太多内容了,完全可以专门作为一门独立的课程存在,所以,本节只会从宏观层面来介绍 RabbitMQ 的消息发送原理,太深的概念并不会涉及。

在了解了如何使用 RabbitMQ 来发送消息之后,简单了解 RabbitMQ 消息发送的原理是非常有必要的,它能够帮助我们定位排查一些 RabbitMQ 出现的问题,所以就让我们来看看 RabbitMQ 到底是如何来发送消息的吧。

本节主要内容:

  • RabbitMQ 整体架构解析;

  • RabbitMQ 消息发送原理概述;

2. RabbitMQ 整体架构解析

RabbitMQ 整体架构是基于 AMQP 协议的,结合 AMQP 协议的架构模型,我们可以得出 RabbitMQ 的整体架构,RabbitMQ 整体架构如下图所示:

消息这一元素在 RabbitMQ 中虽然至关重要,但消息只是 RabbitMQ 处理的目标,并不能作为 RabbitMQ Server 的组成部分,所以,在上图中,我并没有引入消息这一概念,目的就是让各位同学能够看清楚 RabbitMQ Server 的架构到底是什么样的,即 RabbitMQ Server 都是由哪些元素或组件所组成的。

我们都知道,RabbitMQ Server 就是我们的 RabbitMQ 服务器,在 AMQP 协议中,RabbitMQ Server 又被称为 Broker ,这点同学们需要了解。

由图可知,RabbitMQ Server 由 Virtual Host 、Exchange 、Channel 、Queue 四大核心组件所组成。 在核心基础概念小节中,我们已经对这四大核心组件做了相应的介绍,这里就不再赘述了,如果有不清楚的同学,可以到核心基础概念小节中做相应了解。

在一个 RabbitMQ Server 中,只有一个 Virtual Host ,在一个 Virtual Host 中,可以有多个不同名称的 Exchange ,而一个 Exchange 可以与多个 Channel 进行绑定,同时,一个 Queue 也可以和多个 Channel 进行绑定。

即,在一个 RabbitMQ Server 中,有且只有一个 Virtual Host ,在一个 Virtual Host 中,存在多个 Exchange 和 Channel ,以及多个 Queue , 这个对应关系需要同学们知道。

Tips: 关于 RabbitMQ 的整体架构,我们只需要了解到这一层次即可,即我们只要知道了 RabbitMQ Server 都是由哪些元素构成的,以及这些元素的包含关系即可。

3. RabbitMQ 消息发送原理概述

在对 RabbitMQ 的整体架构有一个宏观了解之后,我们还需要对 RabbitMQ 的消息发送原理也有所了解,知道消息在 RabbitMQ Server 是怎样流转的。

同样地,RabbitMQ 消息的发送原理也是基于 AMQP 协议中消息的发送原理,结合 AMQP 消息的发送原理(同学们不需要知道),我们可以得出 RabbitMQ 消息的发送原理。

我们先来看一下,结合 RabbitMQ 整体架构而得出的 RabbitMQ 消息发送原理是怎样的,如下图所示:

由此图,我们可以得出 RabbitMQ 消息发送的步骤:

第一步,生产者将消息生产出来,并将消息发送到 RabbitMQ Server 上,即我们发到 RabbitMQ 中的消息,会首先置于 RabbitMQ Server 中;

第二步,RabbitMQ Server 根据客户端所发来的连接请求,判断将消息传递到哪个 Virtual Host 中,如果我们在连接 RabbitMQ Server 时,没有设置要连接的 Virtual Host 地址,则 RabbitMQ Server 会将我们的消息传递到地址为 “/” 的 Virtual Host 中去;

第三步,在将消息传递到对应的 Virtual Host 中后,Virtual Host 会继续解析我们的连接请求,并在这一步解析出我们需要的 Exchange 的类型,以及 Channel 的名称,Queue 的名称,以及消息和 Exchange 之间是否有 routing_key ,Channel 和 Queue 之间是否有 bidding_key 这些信息;

第四步,Virtual Host 会根据解析出来的这些信息,将消息和 Exchange 进行匹配,相应的,Exchange 也会和对应的 Channel 进行匹配,并最终将 Queue 和 Channel 进行绑定,使消息进入到对应的消息队列中去;

第五步,待消息进入到对应的消息队列中之后,RabbitMQ Server 会返回给我们一个确认应答(确认应答后续会进行介绍),来通知我们,消息已经成功被 RabbitMQ Server 所发送,于是,消费者变回根据一定的策略来从消息队列中获取消费,并最终将该消息消费掉,消息消费之后,也会给我们返回一个确认应答(确认应答后续会进行介绍),告诉我们消息已经成功消费掉了。

以上就是 RabbitMQ 进行消息发送的先后步骤,为了更直观地为各位同学呈现 RabbitMQ 的消息发送原理,我做了一个流程图给大家,如下图所示:

同学们可以根据上述步骤,结合流程图进行学习和验证。

4. 小结

本小节为各位同学介绍了 RabbitMQ 的整体架构,以及 RabbitMQ 的消息发送原理,出于课程设计的初衷,本小节并没有从源码层面对 RabbitMQ 的消息发送原理做深入地剖析,同学们只需要对 RabbitMQ 的消息发送原理做宏观层面上的了解即可。

通过介绍 RabbitMQ 的整体架构,同学们需要了解 RabbitMQ Server 都由哪些主要元素构成,以及他们之间的包含关系。了解 RabbitMQ 的整体结构以及 RabbitMQ Server 的消息发送步骤是应用好 RabbitMQ 的前提,希望同学们注意。

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 中的消息发送模式之后,才能很清楚的知道,什么业务场景哪种消息模式最合适,最后,希望同学们学的开心、码的快乐。

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);
代码块1234

代码解释:

第 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 种交换机都有一个系统性地了解。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多