rabbitmq 官方文档翻译-1

AMQP 0-9-1 模型解释

AMQP 0-9-1 是什么

AMQP 0-9-1(高级消息队列协议)是一种消息传递协议,可使符合要求的客户端应用程序与符合要求的消息传递中间件代理进行通信。

代理及其角色

消息传递代理从发布者(发布它们的应用程序,也称为生产者)接收消息,并将它们路由到消费者(处理它们的应用程序)

由于它是网络协议,因此发布者,使用者和代理都可以驻留在不同的计算机上。

AMQP 0-9-1 模型简介

AMQP 0-9-1模型具有以下世界观:消息发布到exchange,通常与邮局或邮箱进行比较。
然后,Exchange使用称为绑定的规则将消息副本分发到队列。
然后,代理将消息传递给订阅队列的消费者,或者消费者根据需要从队列中获取/拉取消息。


rabbitmq 官方文档翻译-1_第1张图片
image.png

发布消息时,发布者可以指定各种消息属性(消息元数据)。
某些元数据可能由代理使用,但是,其余部分对代理完全不透明,仅供接收消息的应用程序使用。

网络不可靠,应用程序可能无法处理消息,因此AMQP 0-9-1模型具有消息确认的概念:当消息传递给消费者时,消费者会自动或在应用程序开发人员选择来这样做时立即通知代理。当消息确认正在使用时,代理只有在收到该消息(或消息组)的通知时才会从队列中完全删除消息。

在某些情况下,例如,当无法路由消息时,可以将消息返回给发布者,丢弃,或者如果代理实现扩展,则将消息放入所谓的“死信队列”中。
发布者通过使用某些参数发布消息来选择如何处理这种情况。

队列,exchange和绑定统称为AMQP实体。

AMQP是一种可编程协议

AMQP 0-9-1是一种可编程协议,因为AMQP 0-9-1实体和路由方案主要由应用程序本身定义,而不是代理管理员。因此,规定了声明队列和exchange,定义它们之间的绑定,订阅队列等的协议操作。
这为应用程序开发人员提供了很大的自由,但也要求他们了解潜在的定义冲突。实际上,定义冲突很少见,通常表明配置错误。
应用程序声明它们需要的AMQP 0-9-1实体,定义必要的路由方案,并且可以选择在不再使用AMQP 0-9-1实体时删除它们。

exchange和exchange类型

exchange是发送消息的AMQP 0-9-1实体。
exchange接收消息并将其路由到零个或多个队列。
使用的路由算法取决于exchange类型和称为绑定的规则。
AMQP 0-9-1代理提供四种exchange类型:
Direct exchange (Empty string) and amq.direct
Fanout exchange amq.fanout
Topic exchange amq.topic
Headers exchange amq.match (and amq.headers in RabbitMQ)

除了exchange类型,exchange声明了许多属性,其中最重要的是:
名字
持久性 (exchanges在代理重启后仍存在)
自动删除 (exchange 在最后一个队列和他解绑后删除)
参数 (可选,用于插件和特定于代理的特性)

exchange可以是持久的或短暂的。
代理重启后持久化exchange存活,而暂时exchange则不是(当代理重新上线时,他们必须重新声明)。
并非所有场景和用例都要求exchange持久。

默认exchange

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

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

直接exchange

直接exchange基于消息路由密钥将消息传递到队列。
直接exchange对于消息的单播路由是理想的(尽管它们也可以用于多播路由)。
下面是它的工作原理:
队列用路由密钥K绑定到exchange
当具有路由密钥R的新消息到达直接exchange时,如果K = R,则exchange将其路由到队列

直接exchange通常用于以循环方式在多个工作者(同一应用程序的实例)之间分配任务。
这样做时,重要的是要理解,在AMQP 0-9-1中,消息在消费者之间而不是在队列之间进行负载平衡。

直接exchange可以用图形表示如下:


rabbitmq 官方文档翻译-1_第2张图片
image.png

扇出exchange

扇出exchange将消息路由到绑定到它的所有队列,并忽略路由密钥。
如果N个队列绑定到扇出exchange,则当向该exchange发布新消息时,该消息的副本将被传递到所有N个队列。
扇出exchange是消息广播路由的理想选择。
因为扇出exchange将消息的副本传递给绑定到它的每个队列,所以它的用例非常相似:
大型多人在线(MMO)游戏可以将其用于排行榜更新或其他全球活动
体育新闻网站可以使用扇出exchange来近乎实时地向移动客户端分发分数更新
分布式系统可以广播各种状态和配置更新
群聊可以使用扇出exchange在参与者之间分发消息(尽管AMQP没有内置的存在概念,因此XMPP可能是更好的选择)
扇出exchange可以用图形表示如下:


rabbitmq 官方文档翻译-1_第3张图片
image.png

主题exchange

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

主题exchange具有非常广泛的用例。
每当问题涉及多个消费者/应用程序选择性地选择他们想要接收哪种类型的消息时,应考虑使用主题exchange。

使用例子:
分发与特定地理位置相关的数据,例如销售点
由多个工作人员完成的后台任务处理,每个工作人员能够处理特定的任务集
股票价格更新(以及其他类型的财务数据更新)
涉及分类或标记的新闻更新(例如,仅针对特定运动或团队)
在云中协调不同类型的服务
分布式架构/特定于操作系统的软件构建或打包,每个构建器只能处理一个体系结构或操作系统

头exchange

头exchange设计用于在多个属性上进行路由,这些属性更容易表示为消息头而不是路由密钥。
头exchange忽略路由密钥属性。
相反,用于路由的属性取自headers属性。
如果头的值等于绑定时指定的值,则认为消息是匹配的。

可以使用多个头将队列绑定到头exchange以进行匹配。
在这种情况下,代理需要来自应用程序开发人员的另一条信息,即它是否应该考虑与任何头匹配的消息,还是所有头?
这就是“x-match”绑定参数的用途。
当“x-match”参数设置为“any”时,只需一个匹配的头值就足够了。
或者,将“x-match”设置为“all”,强制所有值必须匹配。

头exchange可视为“直接exchange”。
因为它们基于头值进行路由,所以它们可以用作直接exchange,其中路由密钥不必是字符串;
例如,它可以是整数或散列(字典)。

队列

AMQP 0-9-1模型中的队列与其他消息和任务排队系统中的队列非常相似:它们存储应用程序使用的消息。
队列与exchange共享一些属性,但也有一些额外的属性:
Name 名字
Durable(队列将在代理重启后继续存在)
Exclusive(仅由一个连接使用,当该连接关闭时将删除队列)
Auto-delete(至少有一个消费者的的队列在最后一个消费者取消订阅时将被删除)
Arguments(可选;由插件和特定于代理的功能使用,例如消息TTL,队列长度限制等)

在可以使用队列之前,必须声明它。
声明队列将导致它创建(如果它尚不存在)。
如果队列已经存在并且其属性与声明中的属性相同,则声明将不起作用。
当现有队列属性与声明中的队列属性不同时,将引发具有代码406(PRECONDITION_FAILED)的通道级异常。

队列名字

应用程序可以选择队列名称或要求代理为其生成名称。
队列名称最多可包含255个字节的UTF-8字符。
AMQP 0-9-1代理可以代表应用程序生成唯一的队列名称。
要使用此功能,请将空字符串作为队列名称参数传递。
生成的名称将返回给具有队列声明响应的客户端。

队列名称以“amq”开头。保留供代理内部使用。尝试声明具有违反此规则的名称的队列将导致带有回复代码403(ACCESS_REFUSED)的通道级异常。

队列持久性

持久队列持久存储到磁盘,因此可以在代理重启时继续运行。不持久的队列称为瞬态。并非所有场景和用例都要求队列持久。

队列的持久性不会使路由到该队列的消息持久。
如果代理被删除然后重新启动,则在代理启动期间将重新声明持久队列,但是,只会恢复持久性消息。

绑定

绑定是exchange使用(除其他外)将消息路由到队列的规则。
为了指示exchangeE将消息路由到队列Q,Q必须绑定到E.绑定可以具有某些exchange类型使用的可选路由密钥属性。
路由密钥的目的是选择发布到exchange的某些消息以路由到绑定队列。
换句话说,路由键的作用类似于过滤器。

用一个类比来说:
队列就像你在纽约市的目的地
交易所就像JFK机场
绑定是从JFK到目的地的路线。
可以通过零种或多种方式实现它

拥有这一间接层可以实现使用直接发布到队列不可能或非常难以实现的路由方案,并且还可以消除开发人员必须执行的一定数量的重复工作。

如果AMQP消息无法路由到任何队列(例如,因为它没有发布到它的exchange的绑定),它将被删除或返回给发布者,具体取决于发布者设置的消息属性。

消费者

除非应用程序可以消费消息,否则将消息存储在队列中是没用的。
在AMQP 0-9-1模型中,应用程序有两种方法可以执行此操作:
向他们发送消息(“推送API”)
根据需要获取消息(“拉取 API”)

使用“推送API”,应用程序必须表明有兴趣使用来自特定队列的消息。
当他们这样做时,我们说他们注册了一个消费者,或者简单地说,他们订阅了一个队列。
每个队列可以有多个消费者,或者注册一个独占消费者(在消费时排除队列中的所有其他消费者)。

每个消费者(订阅)都有一个称为消费者标签的标识符。它可用于取消订阅邮件。消费者标签只是字符串。

消息确认

消费者应用程序 - 接收和处理消息的应用程序 - 有时可能无法处理单个消息或有时会崩溃。
网络问题也可能导致问题。
这提出了一个问题:AMQP代理何时应该从队列中删除消息?
AMQP 0-9-1规范提出了两种选择:
代理向应用程序发送消息后(使用basic.deliver或basic.get-ok AMQP方法)。
应用程序发回确认后(使用basic.ack AMQP方法)。

前一种选择称为自动确认模型,后一种称为显式确认模型。
使用显式模型,应用程序选择何时发送确认。
它可以在接收消息之后,或者在处理之前将其持久保存到数据存储之后,或者在完全处理消息之后(例如,成功获取网页,处理并将其存储到某个持久性数据存储中)。

如果消费者在没有发送确认的情况下死亡,则AMQP代理将其重新发送给另一个消费者,或者如果当时没有消费者,则代理在尝试重新发送之前将等待至少一个消费者注册相同的队列。

拒绝消息

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

Negative Acknowledgements

使用basic.reject AMQP方法拒绝邮件。
basic.reject有一个限制:无法拒绝多条消息,就像你可以使用确认一样。
但是,如果你使用RabbitMQ,那么有一个解决方案。
RabbitMQ提供AMQP 0-9-1扩展,称为Negative Acknowledgements或nack。

预取消息

对于多个消费者共享队列的情况,能够在发送下一个确认之前指定每个消费者可以一次发送多少消息是有用的。
这可以用作简单的负载平衡技术,或者如果消息倾向于批量发布,则可以提高吞吐量。
例如,如果生产应用程序由于其正在进行的工作的性质而每分钟发送一次消息。

请注意,RabbitMQ仅支持通道级预取计数,而不支持基于连接或大小的预取。

消息属性和有效负载

AMQP模型中的消息具有属性。
有些属性非常常见,AMQP 0-9-1规范定义了它们,应用程序开发人员不必考虑确切的属性名称。
一些例子是
Content type
Content encoding
Routing key
Delivery mode (持久化与否)
Message priority
Message publishing timestamp
Expiration period
Publisher application id

AMQP代理使用了一些属性,但大多数属性都可以通过接收它们的应用程序进行解释。某些属性是可选的,称为标题。它们类似于HTTP中的X-Header。发布消息时设置消息属性。

AMQP消息还具有有效载荷(它们携带的数据),AMQP代理将其视为不透明的字节数组。
代理不会检查或修改有效载荷。
消息可能只包含属性而没有有效负载。
通常使用序列化格式(如JSON,Thrift,Protocol Buffers和MessagePack)来序列化结构化数据,以便将其作为消息有效负载发布。
AMQP对等体通常使用“内容类型”和“内容编码”字段来传达此信息,但这仅限于惯例。

消息可以作为持久性发布,这使得AMQP代理将它们保存到磁盘。
如果重新启动服务器,则系统会确保收到的持久消息不会丢失。
简单地将消息发布到持久exchange或者它被路由到的队列是持久的这一事实不会使消息持久化:这一切都取决于消息本身的持久性模式。
将消息发布为持久性会影响性能(就像数据存储一样,持久性会在性能上产生一定的成本)。

消息确认

由于网络不可靠且应用程序失败,因此通常需要进行某种处理确认。有时只需要确认已收到消息这一事实。有时,确认意味着消息由消费者验证和处理,例如,验证为具有强制数据并持久保存到数据存储或索引。

这种情况非常常见,因此AMQP 0-9-1具有称为消息确认(有时称为acks)的内置功能,消费者可使用该功能来确认消息传递和/或处理。如果应用程序崩溃(AMQP代理在连接关闭时注意到此情况),如果预期确认消息但AMQP代理未收到该消息,则该消息将被重新排队(并且可能立即传递给另一个消费者,如果有的话)存在)。
在协议中内置确认有助于开发人员构建更强大的软件。

AMQP 0-9-1方法

AMQP 0-9-1结构是多种方法。方法是操作(如HTTP方法),与面向对象编程语言中的方法没任何共同之处。AMQP方法分为几类。类只是AMQP方法的逻辑分组。

让我们来看看exchange类,一组与交易所操作相关的方法。
它包括以下操作:
exchange.declare
exchange.declare-ok
exchange.delete
exchange.delete-ok

上面的操作形成逻辑对:exchange.declare和exchange.declare-ok,exchange.delete和exchange.delete-ok。
这些操作是“请求”(由客户端发送)和“响应”(由代理响应上述“请求”而发送)。

连接

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

通道

某些应用程序需要多个连接到代理。但是,不希望同时打开许多TCP连接,因为这样做会消耗系统资源并使配置防火墙变得更加困难。AMQP 0-9-1连接与可被视为“共享单个TCP连接的轻量级连接”的通道复用。

每个客户端做的协议操作都发生在通道上.在一个特定的通道上的通信和其他通道上的通信是完全隔离的,因此每个协议方法都携带通道id(又名 通道数),一个用于客户端和代理找出这个方法是哪个通道.

通道仅存在于连接的上下文中,而不是单独存在。当连接关闭时,它上面的所有通道也是如此。

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

虚拟主机

为了使单个代理可以托管多个隔离的“环境”(用户组,exchange,队列等),AMQP包含虚拟主机(vhost)的概念。
它们类似于许多流行的Web服务器使用的虚拟主机,并提供AMQP实体所在的完全隔离的环境。
AMQP客户端指定在AMQP连接协商期间要使用的vhost。

你可能感兴趣的:(rabbitmq 官方文档翻译-1)