备用交换
概述
有时,希望客户端能够处理交换器无法路由的消息(即,因为没有绑定的队列或没有匹配的绑定)。典型示例包括:
- 检测客户端是否意外或恶意发布了无法路由的消息
- “否则”路由语义,其中某些消息被特殊处理,其余的则由通用处理程序处理
备用交换器(“AE”)是一项功能,可以满足这些用例。
如何定义备用交换器
对于除默认交换器以外的任何交换器,客户端可以使用策略来定义 AE。这是推荐的选项,因为策略可以极大地简化此类选项的更改(例如,在升级期间)。
在现代 RabbitMQ 版本中,默认交换器是代码中的一个特殊约定,而不是一个“真实”的交换器。因此,它不支持备用交换器功能。
或者,客户端可以在声明交换器时提供可选的交换器参数。在策略和参数都指定了 AE 的情况下,参数中指定的 AE 会覆盖策略中指定的 AE。
使用策略进行配置
这是定义备用交换器的推荐方法。
要使用策略指定 AE,请将键“alternate-exchange”添加到策略定义中,并确保该策略匹配需要定义 AE 的交换器。例如:
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
rabbitmqctl set_policy AE "^my-direct$" '{"alternate-exchange":"my-ae"}' --apply-to exchanges
rabbitmqadmin policies declare \
--name "AE" \
--pattern "^my-direct$" \
--definition '{"alternate-exchange":"my-ae"}' \
--apply-to "exchanges"
rabbitmqctl.bat set_policy AE "^my-direct$" "{""alternate-exchange"":""my-ae""}" --apply-to exchanges
rabbitmqadmin.exe policies declare ^
--name "AE" ^
--pattern "^my-direct$" ^
--definition "{""alternate-exchange"":""my-ae""}" ^
--apply-to "exchanges"
这将把“my-ae”的 AE 应用于名为“my-direct”的交换器。策略也可以使用管理插件定义,有关更多详细信息,请参阅策略文档。
使用客户端提供的参数进行配置
不建议使用此方法定义备用交换器。请考虑改用策略(请参阅上文)。
创建交换器时,可以通过在 exchange.declare 方法的 arguments 表中指定键“alternate-exchange”和包含名称的字符串值来选择性地提供 AE 的名称。
当指定了 AE 时,除了对声明的交换器具有通常的 configure 权限外,用户还需要对该交换器具有 read 权限,对 AE 具有 write 权限。
例如:
Map<String, Object> args = new HashMap<String, Object>();
args.put("alternate-exchange", "my-ae");
channel.exchangeDeclare("my-direct", "direct", false, false, args);
channel.exchangeDeclare("my-ae", "fanout");
channel.queueDeclare("routed");
channel.queueBind("routed", "my-direct", "key1");
channel.queueDeclare("unrouted");
channel.queueBind("unrouted", "my-ae", "");
在上面的 Java 代码片段中,我们创建了一个名为“my-direct”的直连交换器,并将其配置为使用名为“my-ae”的 AE。后者被声明为一个扇出交换器。我们使用绑定键“key1”将一个名为“routed”的队列绑定到“my-direct”,并将一个名为“unrouted”的队列绑定到“my-ae”。
备用交换器的工作原理
每当发布到具有已配置 AE 的交换器的消息无法路由到任何队列时,通道就会将该消息重新发布到指定的 AE。如果该 AE 不存在,则会记录一条警告。如果 AE 无法路由消息,它会将其发布到自己的 AE(如果已配置)。此过程将继续进行,直到消息成功路由,达到 AE 链的末端,或者遇到一个 AE 已经尝试路由过该消息。
例如,如果我们使用路由键“key1”将消息发布到“my-direct”,那么该消息将根据标准的 AMQP 行为路由到“routed”队列。但是,当使用路由键“key2”将消息发布到“my-direct”时,该消息不会被丢弃,而是通过我们配置的 AE 路由到“unrouted”队列。
AE 的行为纯粹与路由有关。如果消息通过 AE 路由,它仍然被计为已路由(对于“mandatory”标志而言),并且消息在其他方面保持不变。