本地随机交换机
概述
本地随机交换机(Local random exchange)是 RabbitMQ 4.0 中引入的一种新型交换机。它主要针对请求-响应(“RPC”)用例而设计。使用此类型的交换机,消息始终会被投递到本地队列,从而保证了发布者的延迟降至最低。如果绑定到该交换机的本地队列有多个,则会随机选择其中一个来投递消息。
动机
本地随机交换机旨在与排他队列(exclusive queues)配合使用,为请求-响应(“RPC”)工作负载提供低延迟的组合方案。
该交换机的设计前提是:请求-响应消费者的数量至少与集群节点的数量一样多。如果情况并非如此,部分发布的消息将会被丢弃。
请求/响应(通常称为 RPC)是使用 RabbitMQ 等消息代理实现的一种流行模式。其常见用例之一是微服务架构,即一个服务向另一个服务请求数据。该模式在教程六中有详细介绍。
支持此类场景的关键需求包括:
-
低延迟:发布者可能需要等待响应才能继续后续操作;因此,消息应尽可能快地投递给消费者。使用其他类型的交换机时,队列可能位于不同的节点上,这意味着需要额外的网络跳转才能完成消息投递。本地随机交换机通过始终将消息投递到本地队列来解决此问题。如果该交换机未绑定任何本地队列,则消息将不会被投递。
-
可扩展性:能够通过增加应用实例来处理更多请求。将更多队列绑定到本地随机交换机可以自动将请求分散到更多队列中。消费者可以使用排他队列来确保它们是节点本地(node-local)的。
本地随机交换机与排他队列的结合,确保了发布和消费过程无需在集群节点间传输消息。这保证了最小延迟,并要求集群中的每个节点上至少有一个绑定到该类型交换机的本地队列。因此,应用实例(特别是请求/响应“RPC”消费者)的数量预期(且必须)大于集群中节点的数量。
如何使用本地随机交换机
本节将通过基于 PerfTest 的负载测试来演示此交换机类型的行为。
PerfTest 将模拟客户端应用程序。此工作负载要求使用多节点集群。在下例中,我们假设所有节点都运行在 localhost 上,并监听从 5672 到 5674(含)的三个连续端口。
如果集群不是在本地运行或使用了不同的端口,则需要调整下方的 URI。
假设是一个 3 节点集群,以下命令将启动 5 个消费者:第一个节点上 2 个,第二个节点上 2 个,第三个节点上 1 个。
perf-test -H amqp://:5672 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://:5672 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://:5673 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://:5673 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://:5674 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
PerfTest 将声明排他队列并将其绑定到类型为 x-local-random 的 rpc 交换机上(交换机本身也会被声明)。本地随机交换机不允许在将队列绑定到交换机时使用路由键,因此上述命令使用了 --routing-key '' 选项来覆盖 PerfTest 的默认值。
在路由消息时,路由键会被忽略;完全不使用路由键可以实现一些性能优化。
接下来,必须启动一些生产者。在此示例中,我们使用两个具有不同发布速率的生产者。
perf-test -H amqp://:5672 --consumers 0 --exchange rpc -t x-local-random --rate 100
perf-test -H amqp://:5673 --consumers 0 --exchange rpc -t x-local-random --rate 20
现在,管理控制台(Management UI)的 Queues 选项卡将显示如下内容:

正如预期,节点 rabbit-1(端口 5672)上的队列每个每秒接收约 50 条消息,节点 rabbit-2(端口 5673)上的队列每个每秒接收约 10 条消息,而 rabbit-3(端口 5674)上的消费者没有接收到任何消息,因为该节点上没有本地发布者。
注意事项与局限性
在 RabbitMQ 前面放置负载均衡器实际上会使这种交换机类型无法有效使用。
此交换机类型的设计前提是集群中的每个节点上都有在线的消费者。否则,发布在没有消费者的节点上的消息将会被丢弃。
确保这一点的最佳方法是将消费者配置为连接到特定的节点。如果该节点不可用,则这些消费者也将不可用(这也在预期之内)。
在发布者方面,具有一定的灵活性:如果发布者重新连接到另一个节点,它会增加该节点的负载,但消息流和路由仍应正常工作。然而,仍建议将发布者配置为仅连接到特定节点。与上述消费者建议类似,如果该节点不可用,则此类发布者也将不可用。
发布时可以使用
mandatory标志。如果消息无法路由,这些消息将被退回给发布者。这将允许检测发布者所连接的节点上没有消费者的情况。对于 RPC,不需要发布者确认(Publisher confirms)。在 RabbitMQ 前面放置负载均衡器实际上会使这种交换机类型无法有效使用,因为很难确保所有节点上都有消费者,并使它们均匀分布(虽然这不是必需的,但对于更高效的资源利用而言是最佳的)。因此,强烈建议直接连接到 RabbitMQ 节点。
在这种架构中,队列不一定非要是排他的,但这可以简化某些操作。