Overview

该文档提供了一个AMQP0-9-1协议的概览,该协议是RabbitMQ支持的诸多协议中的一种。

从整体看AMQP0-9-1和AMQP模型

什么是AMQP 0-9-1

AMQP 0-9-1(高级消息队列协议)是一个消息传递协议,它使得某个客户端应用可以与某个消息中间层broker进行通信。

Brokers和它们所扮演的角色

broker接收来此发布者(发布消息的应用,也称作生产者)的消息,并将它们传递给消费者(处理消息的应用)

因为这是个网络协议,发布者、消费者和broker可能在不同的机器上

AMQP 0-9-1 模型简述

AMQP 0-9-1模型的观点是这样的:消息被发布给exchange,exchange通常被比喻成邮局或信箱。之后exchange根据某种规则将消息的副本分配给队列,这种规则被称之为绑定(binding)。之后,broker要么将消息传递给订阅了该队列的消费者,要么消费者通过fetch/pull对消息进行拉取。

当发布消息的时候,发布者可以定义多个消息属性(消息的元数据)。一些元数据是给broker用的,但是剩下的对broker是透明的,且只被接收消息的应用使用。

网络是不可靠的,应用可能没能成功处理消息,所以AMQP 0-9-1 模型有一个消息确认的概念。当一个消息被传递给消费者,消费者会给broker发一个通知,这个通知可以自动发,也可以由开发者决定一个时间来尽快发送。当消息确认开启时,broker只有当它收到了一个消息的确认通知时,才会把它从队列总移除。

在某些情况下,比如当一个消息路由解析失败,那么这个消息可以被返回给发布者、丢弃,如果broker实现了扩展,也可以把它放入一个被称为“dead letter queue”的结构中。发布者通过使用某些参数来控制如何处理这些情况。

队列、exchange和绑定合在一起被成为AMQP实体。

AMQP 0-9-1 是一个可编程的协议

AMQP 0-9-1 是一个可编程的协议,因为AMQP 0-9-1实体和路由规则基本上都是应用自己定义的,而不是broker管理器。因此会有协议操作扩展点用来声明队列和exchange,定义它们之间的绑定,订阅一个队列等等。

这给了应用开发者很大的自由,但是他们也得意识到会有潜在的定义冲突。实际上,定义冲突很少发生,而且通常代表着配置文件出错了。

应用会声明他们所需要的AMQP 0-9-1 实体,定义一些必要的路由规则以及可以在某些实体不再需要的时候对它们进行删除。

exchange和exchange类型

exchange是AMQP实体中用来发送消息的地方。exchange拿到一个消息并通过某些路由规则将消息放入0到多个队列中。路由算法依赖于exchange类型绑定规则。AMQP 0-9-1 broker提供了四种exchange类型:

类型

默认预定义名

Direct exchange

(空字符串)和amq.direct

Fanout exchange

amp.fanout

Topic exchagne

amq.topic

Headers exchange

amq.match(以及在RabbitMQ中的amq.headers)

除了exchange类型,exchange声明时还有很多属性,其中最重要的是:

  • 名称(name)
  • 持久性(durability,exchange在broker重启后不丢失)
  • 自动删除(当最后一个关联队列解除关联的时候,exchange会自动删除)
  • Arguments(可选,插件或者broker特性使用)

exchange可以是持久的或者透明的。持久的exchange会在broker重启的时候不丢失,而透明的exchange却不会(它们在broker重启时必须要重新声明)。并非所有的业务场景都需要一个持久的exchange。

Default Exchange

default exchange是由broker预先声明的一个直接的exchange,没有名字(空字符串).它有一个特性,这让他在简单的应用中特别有用:每一个创建的队列都会自动的和它绑定,路由关键字和队列的名字一样.
比如说,当你声明了一个队列,命名为"search0indexing-online",AMQP 0-9-1的broker就会将它和default exchange绑定,并把路由关键字(本文档中有时候将其成为绑定关键字,binding key)设置成"search-indexing-online".因此,当一个消息被发布到default exchange,并且路由关键字为"search-indexing-online"的时候,它会被分配给"search-indexing-online"队列.换句话说,default exchange让消息看起来像是直接传递给了队列,尽管在技术上是不是这样的.

Direct Exchange

一个direct exchange会基于消息的路由关键字来将其传递给指定的队列.在消息是单播路由的时候这很有用(尽管它也可以用于多播路由).其工作过程如下:

  • 一个队列和exchange绑定,路由关键字是K
  • 当一个路由关键字为R的新消息到达exchagne,如果K=R, exchange就会将其路由到队列中. direct exchange经常被用于多个worker以一种循环方式工作时的任务分发.当这么做时,有一点非常重要,在AMQP 0-9-1中,消息是在消费者之间负载均衡的,而不是在队列之间. 一个direct exchange可以用下图表示:

activemq amqp activemq amqp 0.9.1_消息路由

Fanout Exchange

一个fanout exchange会将消息传递给所有与它绑定的队列,而不是考虑路由关键字.当N个队列与一个fanout exchange绑定,一个新的消息发布到该exchenge的时候,它会给每一个队列发一个消息的副本.fanout exchange在消息广播路由的时候很赞.
因为fanout exchange会将消息副本传递给每一个与它绑定的队列,所以它的使用场景非常类似:

  • 大型多人在线(MMO,massively multi-player online)游戏可以将其用于排行榜更新和其他全局性的事件
  • 运动新闻网站可以用它来发布得分的更新,以实现移动客户端的实时性
  • 分布式系统可以广播不同状态和配置的更新
  • 群聊可以用它在参与者之间传递消息(尽管AMQP没有内置的在线状态的概念,所以XMPP可能是更好的选择)
  • 一个fanout exchange可以用下图表示:
  • activemq amqp activemq amqp 0.9.1_activemq amqp_02


Topic Exchange

topic exchange将消息路由给一个或多个队列,这依赖于消息的路由关键字以及我们用来绑定队列和exchagne的匹配模式.topic exchange常被用来实现各种发布-订阅模式的变体.topic exchange一般用于消息的多播路由.
topic exchange有广泛的使用场景.无论何时,当多个消费者/应用需要选择它们想要接收哪些消息的时候,就应该考虑topic exchange
比如:

  • 与某个地理位置相关的数据的分发,比如销售点
  • 多个worker处理后台任务,每一个都可以处理一部分任务
  • 股票价格的更新(以及其他类型的财务数据的更新)
  • 包含分类或标签信息的新闻的更新(比如说,只针对某个特定的运动或队伍)
  • 分布式体系结构/特定于操作系统的软件构建或打包,其中每个构建器只能处理一个体系结构或OS