我们有一个应用程序,它将使用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")
答案 0 :(得分:34)
假设两个模型都被认为是使用一个代理运行来实现的,那么我可以看到的差别不大。
选择2似乎在现实世界中更常见,以解决这种路由问题(至少在我的轶事经验中),这正是主题交换存在要解决的挑战。
您可能遇到的唯一区别与路由速度有关。我不确定与主题交换中使用的路由密钥技术(包括#
和{{1}之类的通配符)相比,RabbitMQ中的Exchange路由(总是基于精确的字符串匹配)是否更快})。我的预感是,Exchange歧视会更快,但您可以自己试验一下,或尝试联系RabbitMQ团队询问他们。
最后,如果您使用选项1结束了大量队列,那么您将拥有成比例的Exchange扩散。这听起来像一个维护头痛。如果你只有少数几个队列,那么问题不会太多。
答案 1 :(得分:13)
确实,方法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 ...您仍然可以保持单一直接交换。
答案 2 :(得分:6)
对于负载很小的单个小节点,几乎没有什么区别。出于上述原因,大多数人选择选项二。
在设计系统时,您应该问问自己将来如何扩展。
如何扩展?
我需要它来扩展吗?
我想在将来添加高可用性群集吗?
我的路由会改变......
在大多数情况下,选项2提供了更大的灵活性。
它允许您执行诸如使用自己的队列将新使用者附加到Exchange并轻松捕获任何子集或所有消息流的操作。 (这些队列可以在群集中的其他节点上,也可以镜像到n个节点,提供故障转移)典型的用例是使用第4个队列记录所有消息。
如果您的瓶颈在处理方面,您还可以进一步细分您的邮件主题并执行一些优先级,而无需更改您的发布者。示例:ToppicA.urgent,由专门的消费者处理,最终处理TopicA.log。
简短的回答是选项2,除非您有非常具体的性能要求,例如,如果您需要处理超过50k msg / s的持续速率,您可能需要考虑专用节点上的选项1,但是对于正常流量,选项2将更容易扩展和维护。
答案 3 :(得分:0)
直接交换还支持多条路由(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
答案 4 :(得分:0)
还应考虑的一件事是,当您发布到不同的交换机时,与仅使用不同的路由密钥发布到单个交换机时相比,用于发布消息的代码看起来会稍有不同。
请记住,您的代码需要从某个地方(可能是从配置)知道不同交换的名称,并且您必须维护交换和路由键之间的某种映射。同样,在RabbitMQ中直接交换时,路由密钥也需要与队列名称完全匹配。因此,您的代码还需要知道队列名称,以便能够设置正确的路由键。
使用单个交换器(无论是直接交换还是主题交换)时,您的代码仅需要处理一个交换器和路由键。