Shovel 插件
概述
本指南概述了 RabbitMQ Shovel,这是一个核心 RabbitMQ 插件,用于将消息从源单向移动到目的地。另外两篇指南分别介绍了两种 Shovel 类型:动态 Shovel 和 静态 Shovel。本文重点介绍其概念、工作原理以及功能。
动态 Shovel 是现代 Shovel 类型。如有疑问,请优先选择动态 Shovel。
有时,我们需要可靠且持续地将消息从一个集群中的源(通常是队列)移动到另一个集群中的目的地(交换机、主题等)。
rabbitmq_shovel 插件允许您配置多个 Shovel(传输工作进程),它们作为 RabbitMQ 集群的一部分运行,专门负责执行上述任务。
源和目的地可以在同一个集群中(通常在不同的虚拟主机 vhost 中),也可以在不同的集群中。Shovel 支持 AMQP 0.9.1 和 AMQP 1.0 的源和目的地。源和目的地不必使用相同的协议,因此可以将消息从 AMQP 1.0 代理(Broker)移动到 RabbitMQ,反之亦然。
Shovel 的行为类似于一个编写良好的客户端应用程序,它连接到源和目的地,消费并重新发布消息,并在两端使用确认机制来应对故障。
Shovel 在底层使用 Erlang AMQP 0-9-1 和 Erlang AMQP 1.0 客户端。
RabbitMQ 4.2 引入了一种新的协议类型:local(本地)Shovel。本地 Shovel 不使用任何现有协议连接到源或目的地,而是使用内部 API 直接从本地集群的队列中消费和/或发布消息。它们只能在声明 Shovel 的集群上使用。本地 Shovel 与 AMQP 0-9-1 Shovel 共享大部分功能和配置。
为什么要使用 Shovel
Shovel 是分布式消息工具包中一个极简且灵活的工具,可以适应多种应用场景。以下是其一些关键特性和设计目标。
松耦合
Shovel 可以在位于不同地理位置或管理域的代理(或集群)之间移动消息,这些集群:
- 可能具有不同且关联度较低的用途
- 可能运行不同版本的 RabbitMQ
- 可能使用不同的消息传递产品或协议
- 可能具有不同的用户和虚拟主机
广域网(WAN)友好
Shovel 插件在底层使用客户端连接。在发生连接和节点故障时,利用确认和发布者确认(publisher confirms)来确保数据安全。
跨协议和跨产品消息传输
现代 Shovel 版本支持多种协议:AMQP 0.9.1 和 AMQP 1.0。
这意味着可以实现,例如从 AMQP 1.0 代理源到 RabbitMQ 目的地,反之亦然。未来可能会支持更多协议。
灵活性
当 Shovel 连接(无论是到源还是目的地)时,可以将其配置为预先声明其所需的特定拓扑。
虽然通常的做法是在源或目的地所在的代理(或集群)上运行 Shovel,但这并非硬性要求;Shovel 可以运行在完全独立的节点或集群上。
有关集群和联合(federation)的比较,请参阅分布式消息传递指南。
Shovel 的功能是什么?
本质上,Shovel 是一个极简的消息泵。每个 Shovel:
Shovel 配置允许对上述每个过程进行定制。
连接
连接到源代理或目标代理后,可以发出一系列配置好的拓扑声明操作。例如,在 AMQP 0-9-1 端点上,可以声明队列、交换机和绑定。
如果发生故障,Shovel 将尝试重新连接。可以为源和目的地指定多个代理,以便(随机)选择另一个代理进行重连。可以指定重连延迟,以避免因重连尝试导致网络拥塞,或者完全禁止发生故障时的自动重连。
所有针对该源或目的地的配置好的拓扑声明操作,都会在重新连接时重新执行。
消费
Shovel 的消费者会在接收消息时、(重新)发布之后,或从目标服务器收到发布确认后,自动确认消息。
对于 AMQP 0-9-1 和本地 Shovel,被目的地拒绝的消息将被重新入队。对于 AMQP 1.0,被目的地拒绝的消息将被丢弃。
重新发布
大多数发布和消息属性由操作员控制。
Shovel 与队列联合(Queue Federation)有何不同?
队列联合将消息从上游集群的源队列移动到本地(下游)集群的目标队列。这确实与 Shovel 的功能非常相似,但存在几个关键区别:
| 特性 | Shovel | 队列联合 |
|---|---|---|
| 消息移动 | 无条件移动消息 | 仅在上游没有本地消费者时移动消息 |
| 方向性 | 始终是单向的 | 可以是双向或针对多个集群的 N 向 |
入门指南
Shovel 插件包含在 RabbitMQ 发行版中。要启用它,请使用 rabbitmq-plugins
rabbitmq-plugins enable rabbitmq_shovel
管理界面用户可能还希望启用 rabbitmq_shovel_management 插件,以便进行 Shovel 状态监控。
定义 Shovel 有两种截然不同的方式:动态 Shovel 使用运行时参数定义,而静态 Shovel 在 advanced.config 文件中定义。
下面涵盖了每种方法的优缺点。大多数用户应首先考虑动态 Shovel,因为它们易于重新配置和管理。
| 静态 Shovel | 动态 Shovel |
|---|---|
在代理的高级配置文件中定义。 | 使用运行时参数定义。 |
创建和删除需要重启节点。 | 创建和删除无需重启节点。可以随时创建和删除。 |
较少预设,自动化友好度较低:任何队列、交换机或绑定都可以在启动时手动声明。 | 较多预设,自动化友好度较高:Shovel 使用的队列、交换机和绑定将自动声明。 |
注意,在使用 AMQP 1.0 时,可能仍需要在 Shovel 外部创建“节点”,因为该协议不包含拓扑创建功能。
Shovel 连接端点
Shovel 使用 URI 连接到源和目的地。
对于 AMQP 0-9-1,URI 格式遵循 RabbitMQ URI 规范。
对于 AMQP 1.0,格式略有不同,特别是指定连接到哪个虚拟主机的部分(假设目标 AMQP 1.0 代理是 RabbitMQ,因此具有此概念)。
请参阅动态 AMQP 1.0 Shovel 参考以了解更多信息。
Shovel 的认证与授权
该插件在底层使用 Erlang AMQP 0-9-1 和 Erlang AMQP 1.0 客户端来打开到其源和/或目的地的连接。就像任何其他客户端库连接一样,Shovel 连接必须成功通过认证,并被授权访问其试图使用的虚拟主机和资源。这对于源和目的地皆适用。
Shovel 连接的认证和授权失败将被运行该 Shovel 的节点记录到日志中。
本地 Shovel 也受到相同的认证检查。
集群中的 Shovel 故障处理
通常希望确保 Shovel 对源集群、目标集群或托管 Shovel 的集群中任何节点的故障具有弹性。
可以为 Shovel 提供源和目的地端点的列表。在这种情况下,Shovel 将连接到第一个可达的端点。
动态 Shovel 会在启用了 shovel 插件的托管集群的所有节点上自动定义。每个 Shovel 只会在一个随机选择的节点上启动,但会在节点故障时在另一个节点上重启。
静态 Shovel 应在启用了 shovel 插件的托管集群的所有节点的配置文件中进行定义。同样,每个 Shovel 只会在一个节点上启动,并在检测到节点故障时在另一个集群节点上重启。
使用 TLS 保护 Shovel 连接
从 Erlang 26 开始,TLS 实现默认启用TLS 客户端对等方验证。
如果未配置客户端 TLS 证书和密钥对,则启用了 TLS 的 Shovel 将无法连接。对于需要使用对等验证(peer verification)的启用 TLS 的 Shovel,必须配置证书(公钥)和私钥对。
如果不需要对等验证,则可以将其禁用。
要配置 Shovel 使用 TLS,需要:
- 在源和目的地 URI 中,将协议方案使用
amqps代替amqp,并将端口使用5671代替5672(假设使用默认端口,但明确指定了端口) - 在相同的源和目的地 URI 中,通过 URI 查询参数指定 CA 证书、客户端证书/密钥对以及其他参数(即 启用或禁用对等验证、对等验证深度)
- (可选)通过 Erlang 客户端设置配置与 TLS 相关的设置或所有 Shovel 的通用默认值(外加,可选的 联合链接)
在以下示例中,源 URI 不使用 TLS(因为它连接到 localhost,这可能是一个合理的调用),而目的地 URI 被修改为使用带有客户端证书(公钥)和私钥对的 TLS,但禁用了对等验证(为了简单起见,生产环境建议开启)
# Note: this user's access is limited to localhost.
#
# In the following example, the source URI connects to `localhost` and does not use TLS
# while the destination URI is modified to use TLS with peer verification disabled
# for simplicity
curl -v -u guest:guest -X PUT https://:15672/api/parameters/shovel/%2f/my-shovel \
-H "content-type: application/json" \
-d @- <<EOF
{
"value": {
"src-protocol": "amqp091",
"src-uri": "amqp://",
"src-queue": "source-queue",
"dest-protocol": "amqp091",
"dest-uri": "amqps://target.hostname:5671?cacertfile=/path/to/ca_bundle.pem&certfile=/path/to/client_certificate.pem&keyfile=/path/to/client_key.pem&verify=verify_none",
"dest-queue": "destination-queue"
}
}
EOF
这些示例使用带有四个额外 URI 查询参数的 URI:
cacertfile:CA 证书包文件,包含用于签署客户端证书和私钥对的一个或多个 CA 证书certfile:客户端证书(公钥)keyfile:客户端私钥verify:控制对等验证(在此特定示例中,禁用它)
与“常规”客户端连接一样,如果启用 TLS 的 Shovel 需要执行对等验证,则必须在运行 Shovel 的节点上信任服务器的 CA,反之亦然。
本地 Shovel 不使用任何连接,因此不使用 TLS。
监控 Shovel
有两种方法可以发现 Shovel 的状态。
使用管理界面
Shovel 状态可以在管理插件用户界面的管理部分中查看。这需要在用于访问管理界面的节点上启用 rabbitmq_shovel_management 插件。
使用 CLI 工具
可以通过使用 rabbitmqctl 直接查询 Shovel 插件应用程序来获取 Shovel 状态。
# use the -n switch to target a remote node
rabbitmqctl shovel_status
结果将返回一个状态列表,每个运行的 Shovel 对应一项。
列表中的每个元素都是一个包含多个属性的映射:
- 名称
- 类型
- 状态
- 上一次状态更改的时间戳
| 属性 | 描述 |
| 名称 | Shovel 名称 |
| 类型 | 静态 Shovel 为 static,动态 Shovel 为 dynamic |
| 状态 | Shovel 的当前状态 |
| 时间戳 | Shovel 上次进入此状态的时间(例如:成功连接、连接丢失、遇到异常) |
时间戳将返回格式为 {{YYYY, MM, DD}, {HH, MM, SS}} 的本地日历时间。
Shovel 的关键状态为:
| 状态 | 描述 |
| starting | Shovel 正在启动或尝试连接到其配置的端点 |
| running | Shovel 已成功连接并正在运行(从源消费并重新发布到目的地)。此状态将报告一些基本的端点和协议信息。 |
| 已终止 (terminated) | Shovel 已停止或遇到异常。将提供原因。 |