RabbitMQ 中的主题交换与直接交换

Posted

技术标签:

【中文标题】RabbitMQ 中的主题交换与直接交换【英文标题】:Topic Exchange vs Direct Exchange in RabbitMQ 【发布时间】:2012-03-31 01:36:57 【问题描述】:

我们有一个将使用 RabbitMQ 的应用程序,并有几个不同的队列用于在层之间传递消息。

最初,我计划使用多个直接交换,每种消息类型一个,但看起来使用不同路由键绑定的队列与单个主题交换将实现相同的目标。

进行单一交换似乎也更容易维护,但我想知道以一种方式进行这种方式是否比另一种方式有任何好处(如果有的话)?

选项 1,使用多个直接交换:

ExchangeA (type: direct)
-QueueA

ExchangeB (type: direct)
-QueueB

ExchangeC (type: direct)
-QueueC

选项 2,使用单一主题交换:

Exchange (type: topic)
-QueueA  (receives messages from exchange with routing key of "TypeA")
-QueueB  (receives messages from exchange with routing key of "TypeB")
-QueueC  (receives messages from exchange with routing key of "TypeC")

【问题讨论】:

你可以在这里了解不同之处***.com/questions/9704590/…jstobigdata.com/rabbitmq/topic-exchange-in-amqp-rabbitmq 【参考方案1】:

假设这两种模型都被认为是使用一个运行的代理来实现的,我可以看到几乎没有区别。

选项 2 在现实世界中似乎更常见于解决此类路由问题(至少在我的轶事经验中),而这正是主题交换要解决的挑战。

您可能遇到的唯一区别与路由速度有关。与主题交换中使用的路由密钥技术(可以包括#* 等通配符)相比,我不确定RabbitMQ 中的Exchange 路由(始终基于精确的字符串匹配)是否更快。我的预感是 Exchange 歧视会更快,但您可以自己尝试找出答案,或者尝试联系 RabbitMQ 团队询问他们。

最后,如果您选择选项 1 时会出现大量队列,那么您的 Exchange 数量就会成比例地增加。这听起来像是一个令人头疼的维护问题。如果您只有几个队列,那么这不是什么大问题。

【讨论】:

我同意。具有适当路由键的多个队列更容易管理。选项 1 的唯一优势是可以将多个交易所托管在单独的硬件上,从而实现垂直扩展。但是,如果您的硬件摇摆不定,那么您可能永远不需要走这条路。 我认为使用 Topic 的好处是,如果将来您需要将相同的消息发送到 Exchange 中的多个队列,您的选项 2 会更可取。 请注意,当有多个消费者时使用 Direct Exchange,它将作为扇出并将消息发送给所有连接的用户。同时,主题 Exchange 队列将基于循环处理消费者【参考方案2】:

确实,方法 2 更好,因为它让您可以灵活地将单个队列用于多个路由键。

交流话题

QueueA-- binding key = India.Karnataka.*

您可以将消息路由到主题交换,路由键为 India.Karnataka.bangalore,India.Karnataka.Mysore。

以上所有消息都进入QueueA。

直接交换

但我不明白你为什么在方法 1 中创建多个直接交换。你可以有一个直接交换并且有多个队列,每个队列绑定一个唯一的键。

QueueA-- binding key = Key1
QueueB-- binding Key = Key2
QueueC-- binding Key = Key3

所有 key1 消息都进入 QueueA。Key2 进入 QueueB ...您仍然可以保持单个直接交换。

【讨论】:

保持单一的直接交换会影响性能吗? 为什么不能用扇出代替主题?【参考方案3】:

对于负载很小的单个小节点,差别不大。出于上述原因,大多数人选择了选项二。

在设计系统时,您应该问问自己,这在未来会如何扩展。

它将如何扩展? 我需要它来扩展吗? 我以后要添加高可用性集群吗? 我的路线会改变吗...

选项 2 在大多数情况下提供了更多的灵活性。

它允许您使用自己的队列将新的消费者附加到 Exchange 并轻松捕获任何子集或所有消息流。 (这些队列可以在集群中的其他节点上,也可以镜像到提供故障转移的 n 个节点)一个典型的用例是使用第 4 个队列记录所有消息。

如果您的瓶颈在处理方面,您还可以进一步细分您的消息主题并执行一些优先级,而无需更改您的发布者。示例:ToppicA.urgent,由专用消费者处理,ToppicA.log 最终处理。

除非您有非常具体的性能要求,否则简短的回答是选择选项 2,例如,如果您需要处理超过 50k msg/s 的持续速率,您可能需要在专用节点上考虑选项 1,但是对于正常流量,选项 2 将更易于扩展和维护。

【讨论】:

【参考方案4】:

Direct exchange 还支持多路由 (https://www.rabbitmq.com/tutorials/amqp-concepts.html#exchange-direct) ,所以你为什么不使用这样的东西:

ExchangeA (type: direct)
-QueueA
-RoutingA

ExchangeB (type: direct)
-QueueB
-RoutingB

ExchangeC (type: direct)
-QueueC
-RoutingC

【讨论】:

【参考方案5】:

还应考虑的一件事是,当您发布到不同的交换器与发布到单个交换器但仅使用不同的路由键时,您发布消息的代码看起来会略有不同。

请记住,您的代码需要从某个地方(可能来自配置)知道不同交换的名称,并且您必须维护交换和路由键之间的某种映射。同样对于 RabbitMQ 中的直接交换,路由键需要与队列名称完全匹配。因此,您的代码也需要知道队列名称才能设置正确的路由键。

当使用单个交换(无论是直接交换还是主题)时,您的代码只需要处理一个交换和路由键。

【讨论】:

以上是关于RabbitMQ 中的主题交换与直接交换的主要内容,如果未能解决你的问题,请参考以下文章

rabbitmq系列四 之主题交换机

RabbitMQ 2

rabbitmq学习:rabbitmq之扇形交换机主题交换机

RabbitMQ学习 (主题)

RabbitMQ的动态创建交换机、队列、绑定、死信队列,延迟队列代码实现

RabbitMQ学习 :主题交换机