本地随机交换
概述
本地随机交换是 RabbitMQ 4.0 中一种新的交换器类型。它主要设计用于请求-回复(“RPC”)用例。使用此交换器类型,消息始终会被传递到本地队列,从而确保最低的发布者延迟。如果有多于一个的本地队列绑定到该交换器,将随机选择其中一个来传递消息。
动机
本地随机交换类型旨在与独占队列一起使用,为请求-回复(“RPC”)工作负载提供更低的延迟组合。
此交换器类型的设计假定请求-回复消费者数量至少与集群节点数量一样多。如果不是这种情况,一些已发布的消息**将会丢失**。
请求/回复(通常称为 RPC)是使用 RabbitMQ 这样的消息代理来实现的流行模式。一个流行的用例是基于微服务的架构,其中一个服务从另一个服务请求数据。此模式在教程六中有介绍。
支持此类场景的关键要求包括:
-
低延迟:发布者在收到响应之前可能可以继续处理,也可能不能;因此,消息应尽快传递给消费者。对于其他交换器类型,队列可能驻留在不同的节点上,这意味着传递消息需要额外的网络跳数。本地随机交换通过始终将消息传递到本地队列来解决此问题。如果该交换器没有绑定本地队列,则消息将不会被传递。
-
可伸缩性:能够添加额外的应用程序实例来处理更多请求。将更多队列绑定到本地随机交换会自动将请求分散到更多队列。消费者可以使用独占队列来确保它们是节点本地的。
本地随机交换与独占队列的结合可以确保发布和消费过程在消息不跨集群节点传递的情况下进行。这可以确保最低的延迟,并且要求每台集群节点上都至少有一个绑定到此类型交换器的本地队列可用。因此,期望(也是必需的)应用程序实例的数量,特别是请求/回复(“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 将声明独占队列并将它们绑定到 rpc 交换器,类型为 x-local-random(交换器本身也会被声明)。本地随机交换在绑定队列到交换器时不允许使用路由键,这就是为什么上面使用 --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
现在,管理界面的“队列”选项卡将显示类似如下内容:

正如预期的那样,rabbit-1(端口 5672)上的队列每秒接收约 50 条消息,rabbit-2(端口 5673)上的队列每秒接收约 10 条消息,而 rabbit-3(端口 5674)上的消费者不接收任何消息,因为没有本地发布者。
注意事项和限制
在 RabbitMQ 前置负载均衡器将使得有效使用此交换器类型几乎不可能。
此交换器类型的设计假定集群中的每个节点上都有在线消费者。否则,发布到没有消费者的节点的上消息将被丢弃。
确保此点的最佳方法是配置消费者连接到特定的节点。如果该节点不可用,这些消费者也将(并且期望如此)不可用。
在发布者方面,有一些灵活性:如果发布者重新连接到另一个节点,它将增加该节点的负载,但消息流和路由仍应正常工作。但是,仅配置发布者连接到特定节点可能仍值得考虑。就像上面关于消费者的建议一样,如果节点不可用,这类发布者也将不可用。
发布时可以使用
mandatory标志。如果消息无法路由,这些消息将被返回给发布者。这将允许检测发布者连接到的节点上没有消费者的状况。RPC 不需要发布者确认。在 RabbitMQ 前置负载均衡器将使得有效使用此交换器类型几乎不可能,因为很难确保所有节点上都有消费者并且它们均匀分布(这不是必需的,但对于更多事件资源的使用是最佳的)。因此,强烈建议直接连接到 RabbitMQ 节点。
在此架构中,队列不必是独占的,但这可能会简化某些操作。