RabbitMQ 消息路由模式/交换器

泥瓦匠攻城狮

共 3209字,需浏览 7分钟

 · 2023-07-09

1b56633117b139107ffced5cbde733be.webp



RabbitMQ系列》: 1 .  RabbitMQ 与 AMQP 协议
2 RabbitMQ 消息属性详解 3 RabbitMQ 可靠性与性能的平衡
4.  RabbitMQ 消费消息

消息路由模式

RabbitMQ 最强大之处就在于其灵活性:它能根据消息发布方提供的路由信息,将消息路由到不同的队列中。不论是将消息发往单个队列、多个队列、交换器,还是另一个由交换器插件提供的外部源,RabbitMQ 的路由引擎能始终保持极快的速度和灵活性。

通过 direct 交换器路由消息

当需要投递的消息有一个确定的目标(或者多个目标)时,direct 交换器就能派上用场。任何绑定在交换器上的队列,只要它的路由键和发布消息时的一致,它就能收到消息。

对于 direct 交换器来说,RabbitMQ 在检查绑定时会比较字符串是否相等。此时不允许使用任何类型的模式匹配。

如下图,使用了 direct 交换器,消息发布者1发布的消息将会路由至队列1和队列2,而消息发布者2发布的消息将会路由至队列2和队列3中:

14dde4abe8754b97bfe2f1c1c7023cb9.webpdirect

RabbitMQ 内置了 direct 交换器,所以不需要额外的插件。要创建一个 direct 交换器非常简单,只需要将其声明为 direct 即可。

它非常适用于 RPC 消息通信模式下的路由应答消息。对于那些需要使用由多台服务器提供的不同组件的应用来说,使用 RPC 来解除应用耦合正是实现高度可扩展性的良方。

通过 fanout 交换器广播消息

所有发往 fanout 交换器的消息会被投递到所有绑定到该交换器上的队列中。由于 RabbitMQ 不需要在投递消息时检测路由键,这将带来可观的性能优势。

fanout 交换器提供了非常棒的方式,让每一个消费者都能访问到原始数据。不过这也是一把双刃剑,因为消费者无法对收到的消息进行选择。

使用 topic 交换器有选择地路由消息

topic 交换器会将消息路由至匹配路由键的任一队列中。通过采用句点分隔的形式,队列可以通过使用基于通配符的模式匹配的方式来绑定到路由键上。通过使用星号(*)和井号(#)字符,可以在同一时刻匹配路由键的特定部分,甚至是多个部分。星号将会匹配路由键中下一个句点前的所有字符,而井号键将会匹配接下来所有的字符,包括句点。

下图展示了由三部分组成的 topic 交换器路由键:

8e55daa186ef5b19d9af10cfb69ba503.webptopic 交换器

topic 交换器是消息路由的极佳选择,它使得单一用途的消费者能够对消息进行不同的处理。如下图,基于路由键的构造方式,消息会被有选择地路由到不同的队列中去:

49ed3944c2fb942661df21b7dcc39193.webptopic 交换器路由

利用这种体系结构的单一用途的消费者可以更容易维护和扩展。

注意:创建富含消息语义的路由键很有用。它能够描述消息的意图或内容。相对于基于应用程序的细节来设计消息及其路由键来说,基于事件的通用消息通信则鼓励消息的可重用性。当开发人员能够在应用程序中复用现有消息时,代码复杂性降低以及消息吞吐量降低是最显而易见的优势。

当进行路由键的的完全匹配时,topicdirect 交换器之间几乎没有差异。但是,通过使用 topic 交换器,将能对路由键进行部分模式匹配,将来若有其他用途时也不必改动现有的消息通信架构。

使用 headers 交换器有选择地路由消息

headers 交换器通过采用消息属性中的 headers 表支持任意的路由策略。绑定至 headers 交换器的队列会向 Queue.Bind 参数中传入键值对数组以及 x-match 参数。x-match 参数是字符串类型,可以设置为 any 或者 all 。如果将其设置为 any ,同时 headers 表中的值匹配了任何一个绑定值的话,消息就会被路由过去。如果将 x-match 设置为 all 的话 ,那么所有传入 Queue.Bind 中的参数值必须全部匹配才行。这并不排除消息在 headers 表中拥有额外的键值对。

尽管 headers 交换器通过 anyall 匹配能力确实增添了额外的灵活性,但同时也带来了额外的路由计算开销。在使用 headers 交换器路由消息时,headers 属性中的所有值必须在计算值之前按照键的名称进行排序。传统观点认为,由于额外的计算复杂性,headers 交换器比其他交换器类型要慢得多。

交换器间绑定

RabbitMQ 团队往 RabbitMQ 中添加了一种非常灵活的机制(未包含在 AMQP 规范中),允许将消息路由至交换器的任意组合。从而使得应用程序可以使用交换器的一部分功能加上另一种交换器的另一部分功能。

交换器间的绑定类似于队列绑定,与将队列绑定至交换器上不同的是,需要使用 RPC 方法 Exchange.Bind 将一个交换器绑定至另一个交换器上。

当使用交换器间绑定时,绑定交换器的路由逻辑和绑定队列是一致的。任何交换器都可以绑定到任何一个内建类型的交换器上。

作为一种工具,交换器间绑定为消息通信模式带来了巨大的灵活性。但是这一灵活性也伴随着额外的复杂性和开销。

使用一致性哈希交换器路由消息

一致性哈希交换器(consistent-hashing exchange)插件随着 RabbitMQ 一同发布,将数据分发给绑定的队列上。可为用于接收消息的队列做负载均衡。

相比 RabbitMQ 将消息分发至单个队列的多个消费者来说,它提供了潜在的更为快速的吞吐量。当使用数据库或其他系统以消费者的身份直接集成至 RabbitMQ 上时,一致性哈希交换器提供了扩展数据的能力而无须编写中间件。

注意

如果考虑使用一致性哈希交换器来提升消费者吞吐量的话,应当为以下两种场景建立基准测试并加以区分:单队列多消费者和仅有单个消费者的多个队列。这样一来就能辨别出哪一种选择更合适。

一致性哈希交换器采用一致性哈希算法来决定哪个队列将会收到消息。不同于将队列绑定至路由键或者头信息,队列将被绑定至一个基于整型的权重值。算法的一部分采用该权重值来决定消息应如何投递。假设有两个队列绑定在了一致性哈希交换器上,并且这两个队列由相同的权重,那么消息的分发会接近于五五开。

一致性哈希交换器不会轮询(round-robin)消息,而是基于路由键或消息属性中 header-type 值的哈希值来作出明确的路由。不过,相较而言,拥有更高权重的队列将能从交换器接收到更高比例的消息。

值得注意的是,由于一致性哈希算法的工作方式,如果变更了绑定至交换器的队列总数的话,那么消息的分布极有可能会跟着发生变化。

0faeec613f4a16c4f22f95c9332a7b24.webp

记得 转发 在看 关注 哦!
浏览 33
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报