RabbitMQ协议-AMQP 0-9-1 (高级消息队列协议)

工作模型

producer:生产者

Connection:TCP长连接,AMQP 0-9-1 连接通常是长期存在的。AMQP 0-9-1 是一个应用层协议,它使用 TCP 进行可靠传输。连接使用身份验证,并且可以使用 TLS 进行保护。当应用程序不再需要连接到服务器时,它应该优雅地关闭其 AMQP 0-9-1 连接,而不是突然关闭底层 TCP 连接。

Broker:Rabbitmq服务器

vhost(虚拟主机):提供用户组,交换器,队列等资源隔离;一个broker有多个vhost,不同的vhost可以有相同的交换器和队列,同一个vhost只能有同一个交换器和队列。生产者推送消息时指定broker上的vhost。

Exchange:负责将消息按照Routing key分布给指定的队列

Queue:它们存储应用程序使用的消息
队列与Exchange共享一些属性,但也有一些额外的属性:
名字
持久(队列将在Broker重新启动后继续存在)
独占(仅由一个连接使用,当该连接关闭时队列将被删除)
自动删除(当最后一个消费者退订时删除至少有一个消费者的队列)
参数(可选;由插件和特定于Broker的功能使用,例如消息 TTL、队列长度限制等)
在使用队列之前,必须先声明它。如果队列不存在,则声明队列将导致它被创建。如果队列已经存在并且其属性与声明中的相同,则声明将无效。当现有队列属性与声明中的不同时,将引发代码为 406 ( PRECONDITION_FAILED )的通道级异常。

绑定:绑定是Exchange使用(除其他外)将消息路由到队列的规则。要指示交换 E 将消息路由到队列 Q,Q 必须绑定到 E。绑定可能具有 某些交换类型使用的可选路由键属性。路由键的目的是选择发布到交换的某些消息被路由到绑定队列。换句话说,路由键就像一个过滤器。

如果一条消息不能被路由到任何队列(例如,因为它被发布到的交换没有绑定),它会被丢弃或返回给发布者,这取决于发布者设置的消息属性。

Consumer:使用消息。
消费者获取消息的方式:

  • 订阅队列以将消息传递给他们(“推送 API”):这是推荐的选项
  • 轮询(“pull API”):这种方式效率非常低,在大多数情况下应该避免
    使用“推送 API”,应用程序必须表明有兴趣使用来自特定队列的消息。当他们这样做时,我们说他们注册了一个消费者 ,或者简单地说,订阅了一个队列。每个队列可以有多个消费者或注册一个 独占消费者(在消费时从队列中排除所有其他消费者)。
    每个消费者(订阅)都有一个称为 消费者标签的标识符。它可用于取消订阅消息。消费者标签只是字符串。

消息确认
消费者应用程序(即接收和处理消息的应用程序)有时可能无法处理单个消息,或者有时会崩溃。网络问题也有可能导致问题。这就提出了一个问题:Broker应该什么时候从队列中删除消息?AMQP 0-9-1 规范让消费者对此进行控制。有两种确认方式:

  • 在Broker向应用程序发送消息后(使用basic.deliver或basic.get-ok方法)。
  • 在应用程序发回确认后(使用basic.ack方法)。
    前一种选择称为自动确认模型,而后者称为显式确认模型。使用显式模型,应用程序选择何时发送确认。它可以是在接收到消息之后,或者在处理之前将其持久化到数据存储之后,或者在完全处理消息之后(例如,成功获取网页,处理并将其存储到某个持久性数据存储中)。
    如果一个消费者在没有发送确认的情况下死亡,Broker将把它重新传递给另一个消费者,或者,如果当时没有可用的消费者,Broker将等到至少一个消费者注册到同一个队列,然后再尝试重新传递。

拒绝消息
当消费者应用程序接收到消息时,对该消息的处理可能会成功,也可能不会成功。应用程序可以通过拒绝消息向Broker指示消息处理已失败(或当时无法完成)。拒绝消息时,应用程序可以要求Broker丢弃或重新排队。当队列中只有一个消费者时,请确保不要通过一遍又一遍地拒绝和重新排队来自同一消费者的消息来创建无限的消息传递循环。

否定确认
使用basic.reject方法拒绝消息。basic.reject有一个限制:无法像使用确认一样拒绝多条消息。但是,如果您使用的是 RabbitMQ,那么有一个解决方案。RabbitMQ 提供了一个 AMQP 0-9-1 扩展,称为否定确认或nacks。

Channels
一些应用程序需要到Broker的多个连接。然而,同时保持许多 TCP 连接打开是不可取的,因为这样做会消耗系统资源并使得配置防火墙更加困难。AMQP 0-9-1 连接与通道复用,可以被认为是“共享单个 TCP 连接的轻量级连接”。

客户端执行的每个协议操作都发生在通道上。特定通道上的通信与另一个通道上的通信完全分开,因此每个协议方法还带有一个通道 ID(也称为通道号),Broker和客户端都使用一个整数来确定该方法适用于哪个通道。

通道仅存在于连接的上下文中,从不单独存在。当连接关闭时,其上的所有通道也会关闭。

对于使用多个线程/进程进行处理的应用程序,很常见的是为每个线程/进程打开一个新通道,并且它们之间不共享通道。

Exchange类型

交换类型 默认预先声明的名称
Direct exchange (空字符串)和 amq.direct
Fanout exchange amq.fanout
Topic exchange amq.topic
Headers exchange amq.match(和 RabbitMQ 中的 amq.headers)

默认交换
默认交换是Broker预先声明的没有名称(空字符串)的直接交换。它有一个特殊的属性,使它对简单的应用程序非常有用:创建的每个队列都会自动绑定到它,并使用与队列名称相同的路由键。

例如,当您声明一个名为“search-indexing-online”的队列时,AMQP 0-9-1 Broker将使用“search-indexing-online”作为路由键将其绑定到默认交换(在此context 有时称为绑定键)。因此,使用路由键“search-indexing-online”发布到默认交换的消息将被路由到队列“search-indexing-online”。换句话说,默认的交换使得看起来可以将消息直接传递到队列,即使从技术上讲这不是正在发生的事情。

直接交换
直接交换根据消息路由键将消息传递到队列。直接交换是消息的单播路由的理想选择(尽管它们也可用于多播路由)。下面是它的工作原理:

队列使用路由键 K 绑定到交换器
当具有路由键 R 的新消息到达直接交换时,如果 K = R,则交换将其路由到队列
直接交换通常用于以循环方式在多个工作人员(同一应用程序的实例)之间分配任务。这样做时,重要的是要了解,在 AMQP 0-9-1 中,消息在消费者之间而不是队列之间进行负载平衡

Fanout交换
扇出交换将消息路由到绑定到它的所有队列,并且忽略路由键。如果 N 个队列绑定到一个扇出交换器,则当一条新消息发布到该交换器时,该消息的副本将传递到所有 N 个队列。扇出交换是消息广播路由的理想选择。

Topic交换
主题交换基于消息路由键与用于将队列绑定到交换的模式之间的匹配将消息路由到一个或多个队列。主题交换类型通常用于实现各种发布/订阅模式变体。主题交换通常用于消息的多播路由。(Exchange和queue之间的模式匹配)

Headers交换
标头交换设计用于在多个属性上进行路由,这些属性比路由键更容易表示为消息标头。标头交换忽略路由键属性。相反,用于路由的属性取自 headers 属性。如果标头的值等于绑定时指定的值,则认为消息匹配。

可以使用多个用于匹配的标头将队列绑定到标头交换。在这种情况下,Broker需要应用程序开发人员提供的更多信息,即,它应该考虑与任何标头匹配的消息,还是所有这些消息?这就是“x-match”绑定参数的用途。当“x-match”参数设置为“any”时,只需一个匹配的标头值就足够了。或者,将“x-match”设置为“all”要求所有值必须匹配。

对于“any”和“all”,以字符串x-开头的标头 将不会用于评估匹配项。将 "x-match" 设置为 "any-with-x" 或 "all-with-x" 也将使用以字符串x-开头的标头来评估匹配项。

posted @ 2022-08-11 13:42  shigp1  阅读(271)  评论(0编辑  收藏  举报