本地随机交换器
概述
本地随机交换器是 RabbitMQ 4.0 中的一种新的交换器类型。它主要为请求-回复 ("RPC") 用例而设计。使用这种交换器类型,消息总是被传递到本地队列,这保证了最小的发布者延迟。如果绑定到交换器的本地队列有多个,则会随机选择其中一个来传递消息。
动机
本地随机交换器类型旨在与独占队列一起使用,为请求-回复 ("RPC") 工作负载提供更低的延迟组合。
这种交换器类型的设计假设请求-回复消费者的数量至少与集群节点的数量一样多。如果不是这种情况,一些发布的消息将被丢弃。
请求/回复,通常称为 RPC,是使用像 RabbitMQ 这样的消息代理实现的一种流行模式。一个常见的用例是基于微服务的架构,其中一个服务从另一个服务请求数据。该模式在教程六中介绍。
支持这种场景的关键要求包括
-
低延迟:发布者可能会或可能不会在收到响应之前继续进行;因此,消息应尽快传递给消费者。对于其他交换器类型,队列可能驻留在不同的节点上,这意味着需要额外的网络跃点来传递消息。本地随机交换器通过始终将消息传递到本地队列来解决这个问题。如果没有本地队列绑定到此交换器,则消息将不会被传递。
-
可扩展性:添加额外的应用程序实例来处理更多请求的能力。将更多队列绑定到本地随机交换器会自动将请求分散到更多队列中。消费者可以使用独占队列来确保它们是节点本地的。
本地随机交换器和独占队列的组合保证了发布和消费过程在消息不跨集群节点传递的情况下进行。这保证了最小的延迟,并要求每个集群节点上至少有一个本地队列绑定到这种类型的交换器。因此,预期(且必要)应用程序实例的数量,特别是请求/回复 ("RPC") 消费者的数量,大于集群中的节点数量。
如何使用本地随机交换器
本节将通过基于 PerfTest 的负载测试来演示这种交换器类型的行为。
PerfTest 将模拟客户端应用程序。此工作负载需要多节点集群。在下面的示例中,我们假设所有节点都在 localhost
上运行,监听从 5672 到 5674(包括 5674)的三个连续端口。
如果集群不是在本地运行或使用不同的端口,则需要调整以下 URI。
假设一个 3 节点集群,以下命令将启动 5 个消费者:第一个节点上 2 个,第二个节点上 2 个,第三个节点上 1 个
perf-test -H amqp://localhost:5672 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://localhost:5672 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://localhost:5673 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://localhost:5673 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
perf-test -H amqp://localhost:5674 --producers 0 --exchange rpc -t x-local-random --exclusive --routing-key ''
PerfTest 将声明独占队列并将它们绑定到类型为 x-local-random
的 rpc
交换器(交换器本身也将被声明)。本地随机交换器不允许在将队列绑定到交换器时使用路由键,这就是上面使用 --routing-key ''
选项来覆盖 Perftest 默认值的原因。
在路由消息时,路由键将被忽略,完全没有路由键可以实现一些性能优化。
接下来,必须启动一些生产者。在本例中,我们使用两个具有不同发布速率的生产者
perf-test -H amqp://localhost:5672 --consumers 0 --exchange rpc -t x-local-random --rate 100
perf-test -H amqp://localhost:5673 --consumers 0 --exchange rpc -t x-local-random --rate 20
现在管理 UI 中的队列选项卡将显示如下内容
正如预期的那样,节点 rabbit-1
(端口 5672)上的队列每个接收约 50 条消息/秒,节点 rabbit-2
(端口 5673)上的队列每个接收约 10 条消息/秒,而节点 rabbit-3
(端口 5674)上的消费者没有收到任何消息,因为没有本地发布者。
注意事项和限制
RabbitMQ 前面的负载均衡器实际上会使有效使用此交换器类型变得不可能
这种交换器类型的设计假设集群中的每个节点上都有在线消费者。否则,在没有消费者的节点上发布的消息将被丢弃。
确保这一点的最佳方法是将消费者配置为连接到一个特定的节点。如果该节点不可用,这些消费者也将不可用(并且预计不可用)。
在发布者方面,有一些灵活性:如果发布者重新连接到另一个节点,它将增加该节点上的负载,但消息流和路由仍然应该工作。但是,配置发布者为仅连接到一个特定节点可能仍然值得考虑。就像上面的消费者建议一样,如果节点不可用,这种类型的发布者也将不可用。
发布时可以使用
mandatory
标志。如果消息无法路由,此类消息将返回给发布者。这将允许检测发布者连接到的节点上没有消费者的情况。发布者确认对于 RPC 不是必需的。RabbitMQ 前面的负载均衡器实际上会使有效使用此交换器类型变得不可能,因为很难确保所有节点上都存在消费者并且它们均匀分布在它们之间(这不是必需的,但对于更多事件资源使用来说是最佳的)。因此,强烈建议直接连接到 RabbitMQ 节点。
在这种架构中,队列不必是独占的,但这可能会简化一些操作。