备用交换
概述
有时,我们希望让客户端处理那些交换器无法路由的消息(例如,因为没有绑定的队列,或者没有匹配的绑定)。这方面的典型示例包括:
- 检测客户端意外或恶意发布了无法路由的消息
- “否则”路由语义,即某些消息被特殊处理,而其余消息由通用处理程序处理
备用交换器(Alternate Exchange,“AE”)正是为解决这些用例而设计的功能。
如何定义备用交换器
对于除默认交换器之外的任何给定交换器,客户端可以使用 策略 (policies) 来定义 AE。这是推荐的选项,因为策略大大简化了此类选项的变更(例如在升级期间)。
在现代 RabbitMQ 版本中,默认交换器在代码中是一种特殊约定的形式,并非“真正”的交换器。因此,它不支持备用交换器功能。
或者,客户端可以在声明交换器时提供可选的交换器参数。如果策略和参数同时指定了 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”应用为“my-direct”交换器的 AE。策略也可以使用管理插件进行定义,详情请参阅 策略文档。
使用客户端提供的参数进行配置G
不建议使用此方式定义备用交换器。请考虑改用策略(见上文)。
创建交换器时,可以通过在 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。后者被声明为扇出交换器。我们将队列 'routed' 以绑定键 'key1' 绑定到 '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' 标志的判定中仍被视为已路由,且消息本身保持不变。