备用交换
概述
有时,客户希望处理交换无法路由的消息(例如,因为没有绑定的队列或没有匹配的绑定)。这方面的典型示例是
- 检测客户端意外或恶意发布无法路由的消息
- “否则”路由语义,其中一些消息被特殊处理,其余消息由通用处理程序处理
备用交换 (“AE”) 是一个解决这些用例的功能。
如何定义备用交换
对于除默认交换之外的任何给定交换,客户可以使用 策略 来定义 AE。这是推荐的选择,因为策略可以显著简化对这些选项的更改(例如,在升级期间)。
在现代 RabbitMQ 版本中,默认交换是代码中的特殊情况约定,而不是“真正”的交换。因此它不支持备用交换功能。
或者,客户端可以在交换声明时提供可选的交换参数。如果策略和参数都指定了 AE,则参数中指定的 AE 会覆盖策略中指定的 AE。
使用策略配置
这是定义备用交换的推荐方法。
要使用策略指定 AE,请在策略定义中添加键 'alternate-exchange',并确保该策略与需要定义 AE 的交换匹配。例如
- bash
- PowerShell
- cmd
rabbitmqctl set_policy AE "^my-direct$" '{"alternate-exchange":"my-ae"}' --apply-to exchanges
rabbitmqctl.bat set_policy AE '^my-direct$' '"{""alternate-exchange"":""my-ae""}"' --apply-to exchanges
rabbitmqctl.bat set_policy AE "^my-direct$" "{""alternate-exchange"":""my-ae""}" --apply-to exchanges
这将为名为“my-direct”的交换应用“my-ae”的 AE。也可以使用管理插件定义策略,请参阅 策略文档 了解详细信息。
使用客户端提供的参数配置
这种定义备用交换的方式不建议使用。请考虑改用策略(参见上文)。
创建交换时,可以在 exchange.declare
方法的 arguments
表中选择性地提供 AE 的名称,方法是指定键 'alternate-exchange' 和包含名称的字符串值。
如果已指定 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。后者被声明为扇出交换。我们将一个名为“routed”的队列绑定到“my-direct”,绑定键为“key1”,将一个名为“unrouted”的队列绑定到“my-ae”。
备用交换的工作原理
每当发布到具有已配置 AE 的交换的消息无法路由到任何队列时,通道会将消息重新发布到指定的 AE。如果该 AE 不存在,则会记录警告。如果 AE 无法路由消息,它会依次将消息发布到其 AE(如果有)。此过程会一直持续,直到消息成功路由,达到 AE 链的末尾,或者遇到已尝试路由消息的 AE。
例如,如果我们将消息发布到“my-direct”,路由键为“key1”,则该消息将根据标准 AMQP 行为路由到“routed”队列。但是,当我们将消息发布到“my-direct”,路由键为“key2”时,该消息不会被丢弃,而是通过我们已配置的 AE 路由到“unrouted”队列。
AE 的行为纯粹与路由有关。如果消息通过 AE 路由,它仍然被视为已路由,以便于 'mandatory' 标志的目的,并且消息本身不会发生更改。