AMQP 0-9-1 模型介绍



Brokers and their Role: 
Broker从发布者(发布它们的应用程序,也称为生产者)接收消息并将消息发送给消费者(处理它们的应用程序)。
由于它是一种网络协议,发布者,消费者和Broker都可以驻留在不同的机器上。

AMQP-0-9-1 model in Brief:
消息发布到Exchange(通常比作邮局), Exchange然后使用称为 binding 的规则将消息副本分发到队列。 然后,AMQP broker 将消息传递给订阅了队列的 consumer,或者 consumer 根据需要从队列中获取/提取消息。


AMQP模型具有消息确认的概念:当消息传递给消费者时,消费者会自动或在开发人员选择这样做时通知 Broker. 当使用了消息确认,Broker会在收到该消息(或消息组)的通知时从消息队列中完全删除消息。

Exchanges and Exchange Types:
Exchanges是消息被发送到的AMQP实体。 Exchanges会接收一条消息并将其路由到0个或多个队列中。 路由算法取决于Exchange Type和称为 binding 的规则。 
AMQP 0-9-1 Broker 提供四种交易类型: 
NameDefault pre-declared names
Direct exchange(Empty string) and amq.direct
Fanout exchangeamq.fanout
Topic exchangeamq.topic
Headers exchangeamq.match (and amq.headers in RabbitMQ)
除了Exchange type之外,Exchange还有几个重要属性:
* Name
* Durability (exchanges survive broker restart)
* Auto-delete (当最后一个队列unbound之后,该exchange就会被删除)
* Arguments (optional, used by plugins and broker-specific features)

Exchanges可以持久或短暂。 Broker重启后持久的Exchanges仍然存在,而短暂的Exchanges不会(当Broker重新联机时必须重新声明(redeclare))。 
并非所有场景和用例都需要持久的Exchange.

Default exchange是Broker预先声明的没有名称(空字符串)的Direct Exchange. 它有一个特殊的属性,对于简单的应用程序非常有用:每个队列都和与队列名称相同的路由key自动绑定。
例如,有一个队列名为“search-indexing-online”,AMQP 0-9-1 broker 则使用名为“search-indexing-online”的routing key将该队列绑定到 default exchange. 因此,发送到具有routing key “search-indexing-online”的default exchange的消息将被路由到队列“search-indexing-online”.

Direct Exchange:
Direct Exchange基于消息的routing key将消息传递给队列。 Direct Exchange对于消息的单播路由是理想的(尽管它们也可用于多播路由)。 
直接交换通常用于以循环方式在多个worker(同一应用程序的实例)之间分配任务。 
注意:
    在AMQP 0-9-1中,消息在消费者之间做负载均衡,而不是在队列之间。

Fanout Exchange:
Fanout Exchange将消息路由到绑定到它的所有队列,并且routing key被忽略。

Topic Exchange:
Topic Exchange 根据消息的 routing key 和用于将队列绑定到exchange的模式,将消息路由到一个或多个队列。Topic Exchange通常用于实现各种发布/订阅模式。 话题交换通常用于消息的多播路由。
 每当涉及多个消费者/应用程序有选择地选择它们想要接收哪种类型的消息时,应考虑使用Topic Exchange. 

Header Exchange:
Head Exchange基于多个属性进行路由,而忽略routing key. 

可以使用多个 header 将队列绑定到header exchange进行匹配。 在这种情况下,要指定“x-match”绑定参数。 当“x-match”设置为“any”时,只有一个匹配的header就够了;当“x-match”设置为“all”,则强制所有header必须匹配。Header Exchange被视为“Direct Exchange的变种”。 由于基于Header值进行路由,所以可以用作直接交换,其中routing key不一定是字符串,也可以是一个整数或散列。


Queue
队列与Exchange共享一些属性,但也有一些其他属性:

  • Name
  • Durable (队列在broker启动后存活)
  • Exclusive (只有一个连接被使用,当连接关闭时队列将被删除)
  • Auto-delete (当最后一位消费者退订后,队列被删除)
  • Arguments (optional; used by plugins and broker-specific features such as message TTL, queue length limit, etc)

使用队列之前,必须声明它。 声明一个不存在的队列后,该队列将被创建。 
如果队列已经存在并且其属性与声明中的相同,则声明不起作用。 
当现有的队列属性与声明中的不同时,将引发代码为406(PRECONDITION_FAILED)的channel level的异常。

应用程序可以选择队列名称或要求broker为其生成名称。 队列名称最长是255个字节的UTF-8字符。
传递一个空字符串作为队列名称参数, broker 就会为队列生成唯一的队列名称。 生成的名称将通过队列声明的response返回给客户端。
队列名称以“amq”开头,是保留给broker作为内部使用的。 若违反此规则,则会有channel level的异常,其代码为403(ACCESS_REFUSED)。

Queue的持久性
Durable queues被持久化到磁盘,即使broker重启也可以存在。 非Durable的队列称为transient. 并非所有场景和用例都要求队列持久。
如果broke宕掉后又恢复,则durable queue在broker启动期间将被re-declare,从而消息可以被恢复。

Bindings
binding是Exchange用来将消息路由到队列的规则。 为了让Exchange E将消息路由到队列Q,Q必须被绑定到E.
routing key的用途就是选择发布到Exchange的某些特定消息,将它们路由到绑定队列。 换句话说,routing key就像过滤器。

如果AMQP消息无法路由到任何队列(例如,因为绑定到Exchange),那么该消息将被丢弃或返回给发布者,具体取决于发布者设置的消息属性。

Consumers
消费有2种方式:
* Have messages delivered to them ("push API")
* Fetch messages as needed ("pull API")

使用“Push API”,应用程序处理来自特定队列的消息。 这称之为“注册了一个消费者”或“订阅一个队列”。 
每个队列可能有多个消费者,或者注册一个独占消费者(消费时排除队列中的所有其他消费者)。
每个消费者(即订阅者)都有一个称为consumer tag的ID,它可以用来取消订阅的消息。consumer tag是字符串。

消息确认
Broker何时应该从队列中移除消息呢? AMQP 0-9-1规范提出了两种选择:
1. broker向应用程序发送消息后(使用basic.deliver或basic.get-ok AMQP方法)。
2. 应用程序发回确认后(使用basic.ack AMQP方法)。
前者称为自动确认模型,后者称为显式确认模型。
通过显式模型,应用程序可以选择何时发送确认。在接收到消息之后立即发送确认,或者在处理之前但保存到数据存储区域之后发送确认,或者在完全处理消息之后发送确认(例如,成功获取网页,处理并将其存储到某个持久数据存储区中)。

如果消费者在未发送确认的情况下崩溃,则AMQP代理将重新发送给其他消费者。如果当时没有消费者,broker将等待至少一个消费者注册到该队列,然后再重新发送。

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

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

预取消息
对于多个消费者共享队列的情况,能够指定在发送下一个确认之前可以一次性给每个消费者发送多少消息。 这可以作为简单的负载均衡,或者如果消息倾向于批量发布,则可以提高吞吐量。
注意,RabbitMQ仅支持channel level的预取计数,而不支持基于connection或size的预取。

消息的属性与载荷(Payload)
有许多消息的属性是见名知义的:
* Content type
* Content encoding
* Routing key
* Delivery mode (persistent or not)
* Message priority
* Message publishing timestamp
* Expiration period
* Publisher application id

某些属性由broker使用,但大多数属性由consumer来使用。 有些属性是可选的,称为Header,它们与HTTP中的X-Headers类似。 在发布消息的时候,设置消息的属性。

消息可以被发布为持久性消息,broker将它们持久化保存到磁盘。 如果server重新启动,系统会确保接收到的持久性消息不会丢失。 
简单地将消息发布到durable exchange或者将其发送到队列并不会使消息持久化:这完全取决于消息本身的持久模式。 
将消息发布为持久化的消息,会影响性能。

AMQP 0-9-1 Methods
The   AMQP 0-9-1 reference  has full details of all the AMQP methods. 

其中的exchange类具有如下的方法:
* exchange.declare
* exchange.declare-ok
* exchange.delete
* exchange.delete-ok

上述操作形成逻辑对:exchange.declare和exchange.declare-ok,exchange.delete和exchange.delete-ok. 
这些操作是“request”(由客户发送)和“response”(由broker响应上述“request”发送)。

以下是一个例子:
client 使用 exchange.declare 方法请求 broker 来 declare 一个新的 exchange:
如上图所示, exchange.declare 带了几个参数,指定了 exchange name, type, durability 等.
若操作成功, the broker 使用 exchange.declare-ok 方法返回:
exchange.declare-ok 只携带了 channel number. 

以上的事件序列和queue的也很像: queue.declare  和  queue.declare-ok
并不是所有的AMQP methods都有返回。 有些就没有返回(response),比如最常用的 basic.publish.
而另一些方法,比如 basic.get , 可能有不止一个"response".


连接(Connections)
AMQP Connection通常是长期存在的。 AMQP是一种使用TCP进行可靠传输的应用层协议。 
AMQP Connection使用身份验证,并且可以使用TLS(SSL)进行保护。
当应用程序不再需要连接到AMQP broker时,它应该正常关闭AMQP连接,而不是突然关闭底层TCP连接。

Channel
一些应用程序需要多个connection到AMQP broker. 但是,不希望同时打开许多TCP连接,因为这样做会占用系统资源并使配置防火墙变得更加困难。多个channel复用一个 AMQP 0-9-1 connection,即,多个channel共享单个TCP连接。

对于使用多线程/进程的应用程序,通常每个线程/进程都打开一个新的channel,并且不共享它们之间的channel. 特定channel上的通信与另一个channel上的通信完全分离,因此每个AMQP方法都会携带一个channel号,客户端可以使用该channel号来确定该方法适用于哪个channel. 

Virtual Hosts
为了使单个broker可以托管多个孤立的“环境”(用户组,exchange,队列等),AMQP 有 virtual hosts(vhosts)的概念。 
Virtual hosts提供AMQP实体所处的完全隔离的环境。 AMQP客户端在AMQP连接协商期间指定它们使用哪些vhosts.

AMQP是可扩展的
AMQP 0-9-1有几个扩展点:
1. 自定义 exchange type: 这使得开发人员可以自己实现路由方案,如基于地理数据的路由。
2. Exchange和队列声明可以包括一些额外的属性,而这些属性也可以被broker使用。 例如,RabbitMQ中的 per-queue message TTL 就是以这种方式实现的。
3. Broker-specific的协议扩展。 例如,RabbitMQ实现的扩展。
4. 可以引入新的AMQP 0-9-1方法类。
5. Broker可以通过额外的插件进行扩展,比如,RabbitMQ管理前端和HTTP API作为插件实现。
这些功能使AMQP 0-9-1型号更加灵活,适用于各种各样的问题。

AMQP 0-9-1 客户端生态系统
略(这一部分没有什么实质性内容,故从略)


(完)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值