From:http://blog.sina.com.cn/s/blog_4aba0c8b0100p6ho.htmlphp
From: http://blog.sina.com.cn/s/blog_4aba0c8b0100p6hb.htmlhtml
这份文档定义了高级消息队列协议,这个协议使得听从该协议的客户端应用和消息中间件服务器之间可以互相通讯。为了彻底实现互操做性,咱们还定义了消息中间件服务的标准行为。java
咱们面对这个领域有经验的技术读者,同时还提供了足够的规范和指南,一个合适的技术工程师能够根据这些文档在任何硬件平台上用各类编程语言来构建听从该协议的解决方案。c++
AMQP的设计目标之一是它的概念都来自于现有的、无产权阻碍的、普遍推行的标准——好比由互联网工程任务组和万维网颁布的标准。算法
所以,咱们相信仅用众所周知的一些技术就可以实现AMQP服务,好比现有的开源网络程序和电子邮件路由软件或者那些技术专家们所熟悉的技术。数据库
高级消息队列协议使得听从该规范的客户端应用和消息中间件服务器的全功能互操做成为可能。编程
咱们的目标是实现一种在全行业普遍使用的标准消息中间件技术,以便下降企业和系统集成的开销,而且向大众提供工业级的集成服务。缓存
咱们的宗旨是经过AMQP,让消息中间件的能力最终被网络自己所具备,而且经过消息中间件的普遍使用发展出一系列有用的应用程序。安全
为了彻底实现消息中间件的互操做性,须要充分定义网络协议和消息代理服务的功能语义。服务器
所以,AMQP定义网络协议(AMQP是协议!)和代理服务以下:
能够只实现AMQP协议规范中的的部分语义,可是咱们相信明确的描述这些语义有助于理解这个协议。
咱们须要明确的定义服务器的语义,由于全部服务器实现都应该保持这些语义的一致性,不然就没法进行互操做。
所以AMQP模型描述了一套模块化的组件以及这些组件之间进行链接的标准规则。
在服务器中,三个主要功能模块链接成一个处理链完成预期的功能:
使用这个模型咱们能够很容易的模拟出存储转发队列和主题订阅这些典型的消息中间件概念。
一个AMQP服务器相似于邮件服务器,exchage相似于消息传输代理(email里的概念),message queue相似于邮箱。Binding定义了每个传输代理中的消息路由表,发布者将消息发给特定的传输代理,而后传输代理将这些消息路由到邮箱中,消费者从这些邮箱中取出消息。
在之前的中间件系统的应用场景中,发布者直接将消息发送给邮箱或者邮件列表。
区别就在于用户能够控制message queue与exchage的链接规则,这能够作不少有趣的事情,好比定义一条规则:“将全部包含这样这样的消息头的消息都复制一份再发送到消息队列中”。
AMQP模型有如下目标:
AMQP协议是一个二进制协议,拥有一些现代特色:多信道、协商式、异步、安全、跨平台、中立、高效。
AMQP一般被划分为三层:
模型层定义了一套命令(按功能分类),客户端应用能够利用这些命令来实现它的业务功能。
会话层负责将命令从客户端应用传递给服务器,再将服务器的应答传递给客户端应用,会话层为这个传递过程提供可靠性、同步机制和错误处理。
传输层提供帧处理、信道复用、错误检测和数据表示。
实现者能够将传输层替换成任意传输协议,只要不改变AMQP协议中与客户端应用程序相关的功能。实现者还可使用其余高层协议中的会话层。
AMQP模型的设计由如下几个需求所驱动:
AMQP传输层的设计由如下几个主要的需求所驱动,这些需求不分前后次序:
咱们支持各类消息交换的体系结构:
本文档分红两个部分:
AMQP版本用两个版本号表示——主版本号和次版本号。咱们约定版本由主版本号后面加小数点再加上次版本号组成(好比1-3表示主版本号为1,次版本号为3)。
下面这些术语在AMQP规范的上下文中没有特别的意义:
本节说明为了保证AMQP实现之间的互操做性而必须标准化的功能语义。
下面的图展现了AMQP模型的功能组件:
咱们能够将中间件服务器概要的定义为:它是一个数据服务器,它接受消息而且对这些消息作两个主要的处理;它按照任意规则将这些消息路由给消费者,当消费者来不及接受这些消息时,它会将消息存储在内存或者硬盘中。
之前的一些消息中间件服务器把路由和存储这两个任务都交给一个总体式的处理引擎去处理,AMQP模型将一些较小的模块化的插件来组合成更加多元化和健壮的处理引擎。AMQP将这些任务划分红两个不一样的角色:
在交换器和消息队列之间有一个明确的接口组件,名为“绑定器”,稍后咱们会提到这个组件。AMQP的价值来自于如下三个主要特性:
可以建立任意类型的交换器和消息队列(一些类型在标准中已经定义,用户还能够添加一些自定义的类型做为服务器的扩展)。 可以结合交换器和消息队列建立出知足任何需求的消息处理系统。 可以经过协议彻底控制AMQP模型中的组件。事实上,AMQP提供了动态编程的功能语义。
2.1.1. 消息队列消息队列将消息存储在内存或者硬盘中,并按顺序把这些消息传递给一个或者多个消费者应用程序。消息队列是消息存储和分发的实体。每个消息队列都彻底独立。
消息队列有多个属性:私有队列或共享队列,持久存储队列或临时存储队列,永久队列或临时队列。经过选择指望的属性,咱们能够用消息队列来实现传统的中间件实体,好比:
标准的存储转发队列,存储消息,并根据轮询调度的算法向多个订阅者分发消息。 临时回复队列,存储消息,并将消息转发给单个订阅者。回复队列一般是临时的,它对单个订阅者而言是私有的。 订阅队列,存储来自于不一样消息源的消息,并将消息转发给单个订阅者。订阅队列一般是临时的,它对单个订阅者而言是私有的。(别跟主题弄混淆了)这几种队列类型并无在AMQP规范中定义,它们只是展现消息队列如何使用的例子。建立其余类型的队列实体也很简单,好比持久、共享订阅的队列。
2.1.2. 交换器交换器接受从生产者应用程序发送的消息,并根据事先定义的规则将这些消息路由给消息队列。这些规则叫“绑定器”。交换器是匹配和路由消息的实体,也就是说,它检查消息并使用绑定器中的路由表,决定如何将消息转发给消息队列。交换器不存储消息。
术语“交换器”本质上便是一类算法,也是这样一个算法的实例。更准确的说,咱们称之为“交换类型”和“交换实例”。
AMQP规范定义了一些标准交换器类型,它们涵盖了消息传输过程当中基本的消息路由类型。AMQP服务器将提供这些交换器的默认实例,使用AMQP的应用程序还能够添加一些自定义的交换器实例。交换器类型都有各自的名称,服务器能够根据这些名称建立出对应的交换器。交换器实例一样也有名称,应用程序能够在代码中使用这个名称来指明应用程序如何与队列绑定和发布消息。
交换器的概念是为了定义一个模型,AMQP服务器能够利用这个模型来扩展消息路由行为。
2.1.3. 绑定关键字通常状况下,交换器会检查某条消息的消息属性、消息头字段、消息体内容,以及从源端接收到的相似数据,而后决定如何路由这条消息。
在大多数简单的状况下,交换器只检查一个关键字段,咱们称之为“绑定关键字”。绑定关键字是一个虚拟地址,交换器用这个地址来决定如何路由消息。
对于点对点路由,绑定关键字是消息队列的名称。
对于主题发布订阅路由,绑定关键字是主题阶层值(TODO:topic hierarchy value,对规范还不熟悉,不知道这是什么意思)。
在更复杂的状况下,绑定关键字可能会基于消息头字段和/或消息体内容。
2.1.4. AMQP与电子邮件的比较若是咱们和电子邮件系统作一个比较,咱们会发现AMQP中的概念早已存在:
AMQP消息相似电子邮件。 消息队列相似于邮箱。 消费者相似于获取和删除电子邮件的电子邮件客户端。 交换器相似于检查邮件并决定如何路由给邮箱的电子邮件传输代理, 路由关键字对应于电子邮件中的“To:or Cc:or Bcc:”地址,不包含服务器信息(路由动做彻底是在AMQP服务器内部完成的)。 每个交换器实例都相似于单独的电子邮件传输代理进程,处理一些电子邮件子域或者是一些特殊的电子邮件通讯(TODO:handling some email sub-domain, or particular type of email traffic)。 绑定器相似于邮件传输代理中路由表的一个条目。AMQP的强大之处在于咱们能够动态的添加队列(邮箱)、交换器(电子邮件传输代理)、绑定器(路由项),还能够经过不一样的方式将这些组件串联在一块儿,这样作远比简单的将目的地址映射成邮箱名称要灵活得多。
咱们没必要对电子邮件和AMQP作深刻比较,由于它们有本质区别。AMQP须要应付的场景是在服务器中路由和存储消息。(TODO:if only for banal reasons such as maintaining transparent performance)服务器内部路由消息和在服务器之间路由消息须要面对大相径庭的问题,也有着大相径庭的解决方法。
为了在AMQP服务器之间路由消息,用户必须明确创建链接桥——为了在这些分离的实体间传递消息,其中一个AMQP服务器将扮演另外一个服务器的客户端。这种工做方式是为了迎合使用AMQP的企业的须要,由于建立这些链接桥可能须要考虑业务流程、合同契约和安全问题。这个模型也让AMQP“垃圾消息”难以在网络上传播。
2.1.5. 消息流程下图展现了消息在AMQP服务器中的处理流程:
一条AMQP消息由一组消息头属性加上一个非透明的消息体组成。
生产者应用程序首先经过客户端API建立一条消息,将应用数据设置在消息体中,也许还会对某些消息属性赋值,而后为消息设置路由标签——这些标签相似于一个地址,也多是任意结构的标识,最后将消息发送给服务器中的某个交换器。
当消息到达服务器时,交换器将这些消息路由给一组一样存在于服务器中的消息队列。若是消息没法路由,交换器可能会根据生产者的要求,直接丢弃或者拒绝这些消息,或者将它们路由给其余交换器。
一条消息能够存在于多个消息队列,AMQP服务器实现可能会用不一样的技术来应对这样的场景:复制消息、引用计数等,使用不一样的技术并不会影响互操做性,然而,当消息路由到多个消息队列时,这条消息对于每个消息队列而言都是相同的,没有惟一性标识来代表这条消息产生于不一样的复制过程。
当消息到达某个消息队列时,消息队列当即尝试将它经过AMQP协议传递给客户端应用程序。若是消息没法传递,消息队列会保存这条消息,而且等待消费者的订阅。
可被送达的消息将会从内部缓冲区被删除。删除动做可能会当即发生,或者在订阅者成功处理且明确接受消息以后发生。订阅者决定在何时如何接受消息,也能够将消息放回到队列中,或者在没法处理消息的时候拒绝它。
生产者发送消息和订阅者接受消息都是事务性处理过程,当一个应用程序扮演这两个角色时——应用程序常常这样干——先发送和接受消息,而后再提交或者回滚事务。
2.1.5.2. 生产者视角经过与电子邮件系统的比较,咱们能够看到生产者并不是直接将消息发送到消息队列中。直接将消息发送到消息队列会破坏AMQP模型内在的抽象性(TODO:the abstraction in the AMQP Model),就好象是容许电子邮件不通过电子邮件传输代理而直接被投递到邮箱中,这会致使管理员在生产者和邮箱之间难以插入邮件过滤器、处理程序、垃圾邮件检测程序等。
AMQP模型采用与电子邮件系统相同的原理:全部消息被发送到交换器,交换器根据规则信息检查消息,而后将它们路由给其余组件,交换器的这两个动做对于用户来讲都是透明的。
2.1.5.3. 消费者视角当咱们以消费者的视角来审视AMQP时,咱们会发现一些它与电子邮件的不一样之处。电子邮件客户端都被动接受邮件——它们读取邮箱中的电子邮件,可是它们没法决定邮箱应该存放哪些电子邮件。AMQP客户端也能够像电子邮件客户端同样被动的接受消息,也就是说,咱们能够写一个应用程序,这个应用程序被动的接收某个消息队列中的消息。
然而,咱们也容许AMQP客户端执行如下三个操做:
就像是咱们拥有这样的邮件系统:
咱们能够看到AMQP更像是一种编程语言,它可以定义AMQP模型中的各个组件如何链接和交互。这也是咱们的目标之一——经过协议实现系统行为的可编程化。
2.1.5.4. 默认流程大多数集成系统不须要这么精确的定义消息流程。就像针对业余摄影爱好者同样,大多数AMQP用户须要“全自动”模式。AMQP使用两个简单的概念来实现这一点:
事实上,默认的绑定器使得生产者直接将消息发送到消息队列中,它模拟了传统消息中间件中最简单的“发送到目的地”消息分发机制。
虚拟主机由它本身的名字空间和一组交换器、消息队列和全部关联的对象组成。每一个链接必须和某个虚拟主机关联。
客户端在认证以后选择虚拟主机,这要求服务器上全部虚拟主机共享服务器的受权策略,对每个虚拟主机而言,受权策略能够是惟一的。
同一链接中全部信道都和同一个虚拟主机通讯。同一个链接既不可能与不一样的虚拟主机同时通讯,也不可能不重建链接就直接切换链接到另外一个虚拟主机。
协议没有提供建立或者配置虚拟主机的机制,这些机制彻底由服务器自定义。
交换器是虚拟主机中的路由代理。交换器实例(俗称“一个交换器”)接受消息和路由信息(路由关键字),而后将消息发送给消息队列或者是一些AMQP服务器厂商扩展的内部服务。对于每一个虚拟主机内部,交换器有独一无二的名字。
应用程序在其权限范围以内能够自由的建立、共享、使用和销毁交换器实例。
交换器能够是持久的、临时的或者自动删除的。持久交换器会一直存在于服务器,直到它被显式删除;临时交换器会工做到服务器被关闭时为止;而一旦没有应用程序使用自动删除交换器,它就会被服务器自动删除掉。
服务器提供了一组特定的交换器类型,每个交换器类型都实现了一种特定的匹配和路由算法,咱们将在下一节介绍这些算法。AMQP要求服务器实现至少实现一小部分交换器类型,而且建议实现更多的类型以知足应用的须要,每个服务器实现还能够实现其余自定义交换器类型。
交换器可以并行的将一条消息路由到多个消息队列,这将建立多个被独立消费的消息实例。
2.3.1. 交换器类型每个交换器类型都实现了一种特定的路由算法。后面将会介绍一些标准交换器类型,可是有两种类型特别重要:
请注意:
2.3.1.1. 直接式交换器类型 (Direct Exchange)直接式交换器类型提供了这样的消息路由机制:经过精确匹配消息的路由关键字,将消息路由到零个或者多个队列中,绑定关键字用来将队列和交换器绑定到一块儿。这让咱们能够构建经典的点对点队列消息传输模型,不过和任何已定义的交换器类型同样,当消息的路由关键字与多个绑定关键字匹配时,消息可能会被发送到多个队列中。
直接式交换器的工做方式以下:
服务器必须实现直接式交换器类型,必须在每个虚拟队列中事先声明至少两个直接式交换器:一个名为“amq.direct”,一个没有公共名称——做为向其余服务器传输消息的默认交换器(无名交换器)。值得注意的是,消息队列可使用任意合法的绑定关键字,可是一般会使用它们本身的名称做为绑定关键字。
特别强调的是,全部使用各自消息队列名称做为绑定关键字的消息队列必须自动和无名交换器绑定在一块儿。
2.3.1.2. 广播式交换器类型(Fanout Exchange)广播式交换器类型提供了这样的路由机制:不论消息的路由关键字是什么,这条消息都会被路由到全部与该交换器绑定的队列中。
广播式交换器类型的工做方式以下:
不使用任何参数将消息队列与交换器绑定在一块儿。 发布者(直接式交换器类型描述中的producer变成了publisher,已经隐含了二种交换器类型的区别)向交换器发送一条消息。 消息被无条件的传递到全部和这个交换器绑定的消息队列中。服务器必须实现扇出式交换器类型,必须在每个虚拟队列中事先声明至少一个扇出式交换器:名为“amq.fanout”。
2.3.1.3. 主题式交换器类型(Topic Exchange)主题式交换器类型提供了这样的路由机制:经过消息的路由关键字和绑定关键字的模式匹配,将消息路由到被绑定的队列中。这种路由器类型能够被用来支持经典的发布/订阅消息传输模型——使用主题名字空间做为消息寻址模式,将消息传递给那些部分或者所有匹配主题模式的多个消费者。
主题交换器类型的工做方式以下:
绑定关键字用零个或多个标记构成,每个标记之间用“.”字符分隔。绑定关键字必须用这种形式明确说明,并支持通配符:“*”匹配一个词组,“#”零个或多个词组。
所以绑定关键字“*.stock.#”匹配路由关键字“usd.stock”和“eur.stock.db”,可是不匹配“stock.nasdaq”。
这种交换器类型是可选的。
服务器应该(不是必须)实现主题式交换器类型,在这种状况下,服务器必须事先在每个虚拟主机中定义至少一个主题式交换器:名为“amq.topic”。
2.3.1.4. 消息头式交换器类型消息头式交换器类型提供了复杂的、多重部分表达式路由,它的路由机制基于AMQP消息头属性。
消息头式交换器的工做方式以下:
消息队列根据一个参数列表与交换器绑定,列表中的参数包括被匹配的消息头字段和一些可选的字段值。 发布者向交换器发送一条消息,这条消息的消息头属性包含了名值列表。 若是消息头中的名值列表与参数列表匹配,消息将被传递给对应的消息队列。匹配算法由参数列表中的某个特殊的名值对所控制,这个参数的名称是“x-match”,它能取一到两个值,用来决定如何匹配其余名值:
若是符合如下两种条件之一,绑定参数中的一个字段与消息头中的一个字段匹配:(1)绑定参数的某个字段没有值,且消息头有这个属性字段;(2)绑定参数的某个字段有值,且消息头中有这个属性字段并具备相同的值。
除了‘x-match’,以“x-”开头的字段都做为保留字段,目前这些字段会被服务器直接忽略。
服务器应该(不是必须)实现消息头式交换器类型,在这种状况下,服务器必须事先在每个虚拟主机中定义至少一个消息头式交换器:名为“amq.match”。
2.3.1.5. 系统交换器类型系统交换器的工做方式以下:
AMQP规范以“amq.”开头的系统服务名称,这些名称做为保留名称,其余全部名称均可以由服务器实现任意使用。这个交换器类型是可选实现的。
2.3.1.6. 自定义交换类型全部没有在规范中定义的交换器类型的名称必须以“x-”开头。不以“x-”开头的交换器类型做为保留类型,被AMQP标准在未来使用。
2.3.2. 交换器生命周期每个AMQP服务器都会事先建立一些交换器(更准确一点,“交换器实例”)。这些交换器会一直存在与服务器中,它们不能被销毁。
AMQP应用程序也能建立它们本身的交换器,AMQP并不使用“create”之类的命令,它使用“declare”命令,这意味着“若是不存在就建立,不然继续”。应用程序能够建立一个私有的交换器,而且当它们的工做完成时删除这些交换器。AMQP提供了一个命令来删除交换器,可是通常应用程序不会这样作。
在本章的例子中,咱们假设全部交换器都在服务器启动时被建立出来。咱们不会展现应用程序如何声明交换器。
消息队列是一个具名缓冲区,它们表明一组消费者应用程序保存消息。应用程序在其权限范围以内能够自由的建立、共享、使用和消费消息队列。
消息队列提供了有限制的先进先出保证。服务器会将从某一个生产者发出的同等优先级的消息按照它们进入队列的顺序传递给某个消费者,万一某些消息不能被消费者处理,它们可能会被打乱顺序从新传递。
消息队列能够是持久的、临时的或者自动删除的。临时消息队列会工做到服务器被关闭时为止;而一旦没有应用程序使用自动删除消息队列,它就会被服务器自动删除掉。只要用户(客户端)拥有相应的权限,任何队列均可以被显式删除。
消息队列将消息保存在内存、硬盘,或者这两种介质的组合之中。
消息队列限定在虚拟主机范围之中。
队列名必须包含1到255个字符。队列名首字符限定为字母a-z或者A-Z,数字0-9,或者下划线‘_’;接下来的其余字符必须是合法的UTF-8字符。
消息队列保存消息,并将消息分发给一个或多个订阅客户端。
消息队列会跟踪消息的获取状况,消息要出队就必须被获取(acquire和consume是两个动做,先执行acquire,至关于对消息加锁)。这阻止了多个客户端同时获取和消费同一条消息,也能够被用来作单个队列多个消费者之间的负载均衡。
若是消息被客户端释放或者最初被发送的消息没有被获取,一个队列中的消息可能会被发送给多个客户端。为了容许客户端可以安全的浏览队列中的内容,消息队列可能会将未被获取的消息分发给客户端。
2.4.1. 消息队列属性当客户端应用程序建立消息队列时,它能够为这个消息队列选择几个重要的属性:
名称——当应用程序共享一个消息队列,它们预先协商好的消息队列名。 持久的——若是指定这个属性,消息队列会在服务器重启以后仍然可以继续工做。不过在重启以后,消息队列会丢失非持久消息。 自动删除的——若是指定这个属性,当全部客户端再也不使用这个队列时,服务器会当即或者不久以后把这个队列删除掉。下面是两种主要的消息队列生命周期:
持久消息队列,在多个订阅者之间共享,独立存在——也就是说,无论有没有订阅者接收消息,它们都会持续存在并收集消息。临时消息队列,私有的,只有某个订阅者可使用,当订阅者退出链接后,消息队列会被删除掉。还有些其余类型的消息队列生命周期,好比共享消息队列,当最后一个订阅者退出链接后,消息队列会被删除掉。
下图展现了临时消息队列的建立和删除过程:
绑定器表示消息队列和交换器之间的关联关系(对于实现者和用户而言,binding应该是一个实体,而不是抽象的relationship)。绑定器指定了路由参数,这些参数告诉交换器哪些消息能够发送给队列。
应用程序根据须要建立和销毁绑定器,驱动消息流入消息队列。绑定器的生存期由使用它的消息队列和交换器决定,当消息队列或者交换器被销毁,绑定器也会被销毁。
客户端应用程序使用命令构造绑定器,用来绑定它正在使用的消息队列和交换器。咱们能够下面这段伪代码来表示一个绑定命令:
Exchange.Bind <exchange> TO <queue> WHERE <condition>
Exchange.Bind的特殊语义取决于交换器类型。
让咱们来看看三个典型的用例:共享队列、私有回复队列和发布订阅队列。
2.5.1. 构造共享队列共享队列是典型中间件中的点对点队列。在AMQP中,咱们可使用默认的交换器和默认的绑定器,假设咱们的消息队列名为“app.svc01”,咱们下面的伪代码来建立共享队列:
可能会有多个消费者使用这个共享队列,假设每一个消费者都用下面的伪代码消费队列中的消息:
为了向共享队列发布消息,每一个生产者用下面的伪代码向交换器发送消息。
回复队列一般属于临时队列,它们也一般属于私有队列,也就是说它们只被某一个订阅者使用。除了这些特色,回复队列使用和标准队列相同的匹配规则,所以咱们一样可使用默认交换器。为了不不一样的客户端使用的临时队列的名字冲突,建议客户端在队列名中包含一个全局惟一标识符(在RFC-4122中定义)或者其余全局惟一标识符。
客户端使用下面的伪代码建立一个回复队列:
为了向回复队列发布消息,生产者用下面的伪代码向默认交换器发送消息:
在经典消息中间件中,单词“订阅”的意义有点模糊,它至少涉及到两个不一样的概念:一组匹配消息的规则和存储匹配消息的临时队列。AMQP将这些工做划分开,由绑定器和消息队列共同完成。
经过匹配主题、消息字段或者消息内容等不一样方式,发布订阅队列从多个不一样的消息源收集消息。发布订阅队列和有名或回复队列之间的关键区别在于:发布订阅队列的名称并不用于路由,它采用抽象的匹配规则完成路由操做,而不是经过路由关键字与队列名一对一匹配的方式。
让咱们来看看什么是发布订阅主题树以及如何实现它。咱们须要一个交换器类型可以在主题树上作匹配操做。在AMQP规范中,这种类型是主题交换器类型。主题交换器用相似于“STOCK.USD.*”的通配符扩展绑定关键字来匹配相似于“STOCK.USD.*”的路由关键字。
咱们不能使用默认交换器或绑定器,由于它们不支持主题式路由。所以咱们显式建立一个绑定器。下面这段伪代码建立和绑定一个发布订阅队列:
一旦绑定器被建立,消息将从交换器路由到消息队列,然而,消费者必须从队列中消费消息:
为了向发布订阅队列发布消息,生产者用下面的伪代码发送消息
主题式交换器使用它的绑定列表来匹配消息中的路由关键字(“STOCK.USD.IBM”),一旦匹配成功,它将消息路由到订阅队列中。
消息是路由和入队原子单位。消息由消息头和消息体组成,其中消息头包含一组明肯定义的属性,消息体是一段对于队列而言不透明的二进制数据。
消息能够是持久的——就算是遇到网络故障、服务器崩溃和服务器过载等一系列问题,服务器也会将持久消息安全的保存在硬盘中,而且保证这些消息会被传输给客户端。
消息能够有优先级,在同一个消息队列中的高优先级消息可能会比低优先级的消息更早被发送给客户端。当消息必须被丢弃时,服务器会先丢弃低优先级消息。
服务器不会更改消息体,可是可能会在转发消息给消费者应用程序以前更改某些消息头属性。
2.6.1. 流控制根据接收方的可用资源,流控制能够被用来匹配消息的传输速率。接收者多是从客户端接收消息的AMQP服务器,也多是从服务器消息队列中接收消息的客户端。这两种状况都采用一样的流控制机制。流控制通常采用信用度的概念来表示发送者还能发送多少消息或者多少字节数据,当发送消息或者数据后,信用度下降,当接收者释放被占用的资源后,信用度提升。预取缓冲区能够被接收者用来减小延迟。
2.6.2. 传输响应当消息被接收时,消息接收者向发送者发回一个信号。当客户端向服务器发送一条消息时,服务器向客户端发回一个接受消息,代表服务器已经成功将消息路由到队列中。当服务器向客户端发送一条消息时,客户端向服务器发回一个接受消息,代表客户端已经成功处理了该消息,并通知服务器从队列中删除该消息。AMQP规范支持两个不一样的接受模式:
显式,接收应用程序必须为其接收到的每条消息或者每批消息向发送者发回一条接受消息。 None(TODO:在AMQP中,有accept-mode和acquire-mode,它们之间互相影响),认为消息被发送出去时就已经被接受了。咱们使用单词“订阅”来表示实体:控制某个客户端应用程序如何接收队列中的消息。这和发布订阅消息传输中的订阅者概念并不冲突。当客户端“启动一个订阅”,它在服务器上建立一个订阅实体。当客户端“取消一个订阅”,它在服务器上销毁一个订阅实体。
订阅属于单独的客户端会话,并致使消息队列将消息异步的发送给客户端。
AMQP规范定义了两种大相径庭的事务模型,单阶段提交事务模型(称为tx)和两阶段提交事务模型(称为dtx)。标准的单阶段提交事务模式的做用域为单个会话,客户端能够选择会话是不是事务性的(使用tx.select命令),一旦选择事务性会话,会话会一直保持事务性直到它被销毁。
一旦选择事务性会话,由客户端发出的全部指示会话传输和接受消息的命令只会在发出tx.commit命令以后生效。其余改变服务器状态的命令并不是事务性命令,所以也没法回滚,好比声明队列和交换器的命令就是非事务性命令。
若是AMQP客户端在一个事务中向服务器发布一条消息(使用message.transfer命令),而后消息会被交换器路由到队列中,直到这个事务完成以后才会从队列中被传递给其余端点。服务器在消息被发送的时候(而非事务被提交的时候)就决定消息是否能被路由到队列中。服务器拒绝接受某条消息不会致使事务回滚,也不会等到commit命令生效的时候才执行,而是在消息被发送到服务器上的时候就当即执行。
事务回滚对服务器所形成的影响是:客户端发出的发布和接受的命令都会被丢弃。须要注意的是获取消息的命令并不是事务性操做,所以在事务做用域中的客户端仍然能够获取消息。这意味着事务回滚以后,客户端仍然持有全部在事务中服务器传递给它的消息(不管客户端是否已接受)。若是客户端但愿服务器可以从新分发这些消息,它必须发出对应消息的释放命令。(事务回滚时,消息的状态是acquired,见2.6.2节,此时若是但愿服务器可以从新分发这些消息,必须发出message.release的命令)
分布式事务支持X-Open XA架构。
dtx类被用来限定和协调事务。dtx.start和dtx.end命令限定在会话中一个AMQP事务的范围。事务的协调和恢复功能由其余dtx类中的命令提供。
OMG OTS和JTS/JTA模型依赖于“资源管理器客户端”实例,这个实例提供了操做全局事务中服务器资源的XA接口的实现。这些资源管理客户端实例由Rmid惟一标识,这个标识贯穿c/c++中的xa_switch或者java中的XAResource的使用过程。
以下图所描述的,一个资源管理器使用XA接口来限定事务的范围和协调事务的结果。当资源管理器客户端使用dtx.start和dtx.end命令参与到会话中的某个事务时,应用程序才能以事务性的方式发送和接收消息。资源管理器客户端使用dtx的相关命令来协调事务结果和恢复AMQP服务器的操做。图中的协调会话就是为了这个目的。
下图展现了应用程序以事务方式从队列Q1消费消息的场景(经过事务管理器TM使用事务T1)。根据消费到的消息,应用程序使用数据库管理系统更新数据库表Tb,而后以事务方式向Q2发送一条消息。
如下是我读后的一些翻译。一家之言,请斧正。
原译文:私有队列或共享队列,持久存储队列或临时存储队列,持久队列或临时队列(durable修饰消息存储,permanent修饰队列,咋翻译?)
个人翻译:私有队列或共享队列,持久化存储队列或临时存储(如存储于内存中)队列,永久队列或临时队列
原译文:对于主题发布订阅路由,绑定关键字是主题阶层值
个人翻译:对于主题发布订阅路由,绑定关键字是该主题自精向粗逐级的关键字
原译文:当消息队列将消息提交给订阅者以后(TODO:can deliver和提交以后貌似不一样,我理解错了吗?),它将消息从内部缓冲区删除。
个人翻译:对于可被送达的消息,它将消息从内部缓冲区删除。
原译文:直接将消息发送到消息队列会破坏AMQP模型内在的抽象性(TODO:the abstraction in the AMQP Model)
个人翻译同样。
原译文:交换器(TODO:Exchanges are named on a per-virtual host basis)
个人翻译:对于每一个虚拟主机内部,交换器有独一无二的名字。
原译文:扇出式交换器类型(TODO:fanout如何翻译?)
个人翻译:广播式交换器类型
原译文:流控制能够被用来比较接收者中保存消息的资源占用率。(TODO:Flow control may be used to match the rate at which messages are sent to the available resources at the receiver.)
个人翻译:根据接收方的可用资源,流控制能够被用来匹配消息的传输速率。
一、永久队列或临时队列,3ks
二、这里的主题的层级有点问题,参考规范中的解释,层级式的主题名示例:asia.china.stock.com1,asia.china.com2,以小数点分隔的层次关系对主题进行了分类
三、可被送达的消息,3ks
四、无
五、交换器有独一无二的名字,3ks
六、广播式交换器类型,3ks
七、比原翻译要通顺不少…
很是感谢您的留言。
我也翻译一段吧,有些地方翻得很差,请各位提出来。
3.1 Session定义
Session 是AMQP对等端之间的命名的交互,session 名局限于一个认证机构(authentication principal),而且session名字由应用层程序来决定。在参与交互的对端之一,或者二者上可能保存session的状态。发布一个消息,建立一个队列,或者选择一个事务模式的命令必须发生在一个session的context以内。
Session是AMQP其余部分的基础。
Session 能够被看作:
AMQP内建的恰好一次递交操做的context
网络协议映射和model层之间的接口
诸于队列,交换器,订阅这些实体的生命周期的一个范围域
命令标识符的一个范围域
3.1.1 session 生命期
Session 不是显式地被建立或者被摧毁,在某种意义上,session 一直存在。对等端必须试着去附着(attach)到它的对端的session上,而不是去建立一个session。而后,这个附着请求的接收者会去查看它是否正持有该session的状态。
对端双方在附着到一个session上,它们必须保留session的相关状态。当session分离了(无论是经过显式的分离请求,仍是对等端之间的网络链接断开),那么session的状态还会被保留一段时间,这个时间是由先前对等端双方协定好的。
3.1.2 命令传输
AMQP模型的交互是经过在对等端之间发送”命令”。这些命令高效地在session上发送。当一个命令从model层到session时,它被授予一个标识符。这些标识符可以用来把命令和其结果关联起来,或者在异步AMQP命令流上执行同步。
3.1.3 session 做为一个层次
Session 充当了网络协议映射层和model层之间的接口。尤为是,当对等端双方都保留session的状态时,它能够被用来做为一个机制,保证命令恰好递交一次。
Session state 至少由以下组成:
一个replay 缓存区,存放对等端尚未确认收到的整个命令,或者命令的一部分
一个幂等的栅栏 – 一组命令标识符,对等端知道这些命令已经接收到了,可是不能肯定对方是否是会重发。
由于session名是由应用层程序指定的,除了这里详细说明的状态以外,可能还有其余更多的状态。这些额外的状态可能(例如)在session状态过时是,会被用来执行恢复。然而,在这章,当咱们谈到session状态,咱们将只会指session层持有的那些状态。
3.2 session 的功能
Session 层提供了几个关键的服务,model层构建在这些服务之上:
命令顺序化标识
将要执行命令的确认
命令完成时发通知
网络失败的重放,恢复
对端失败后,状态协调
3.2.1 顺序化的标识
对等端发出的每一个命令必须被标识,为了在整个系统内,能保证命令恰好一次执行。
Session层使用一个顺序编号的机制来标识每一个命令,使得命令在一个session内是惟一的。
标识这个概念,使得能够异步地把命令和起结果关联起来。Model层能够看到命令的标识符。当一个命令的结果返回时,能够用命令标识符来关联到是哪一个命令的执行结果。
3.2.2 确认
为了使对等端可以安全地丢弃一个给定命令的状态,它必须接收到一个该命令将会被执行的保证。更精确地说,发送者必须接收到一个确认该命令已经被执行,或者它的递交被保留到指望的时间长度。
实际上,你可能会经过一个消息传输系统发送两种类型的消息:持久消息和瞬间消息。对于瞬时消息,通常来讲,消息传输系统和应用程序之间的协定是,消息可能在消息传输系统丢失瞬时状态时,消息可能会被丢失。对于一个持久消息,消息传输系统必须保证消息被保存在最持久的的存储中。
Session 层处理消息确认的发送和接收。这使得session层能够管理它须要持有的状态,可以在对等端临时失败时,或者传输失败时,经过这些状态可以进行恢复。
确承认以批量或者不肯定地延迟。尤为是若是一个对等端不须要紧急的确认通知,确承认以被忽略掉,由于它仅仅是意味着一个命令的完成。
3.2.3 命令完成
从确认概念独立出来的是命令完成概念。为了同步和确保不一样session间的彻底有序化的目的,所以颇有必要在一个命令执行完成时通知到对等端。
在对等端没有请求紧急完成通知的地方,好比通知能够延迟或者能够批量发送,这适用于一命令范围。这减少了网络的流量。
例如,若是3个队列按顺序声明,如命令1到3。服务器可能会像以下这下通知命令完成
注意,命令的接收方将会发送整个已经完成的命令集(这里不明白啥意思,比较难翻)
3.2.4 重放和恢复
通常地,AMQP系统应该可以处理临时的网络失败,或者AMQP 服务器cluster 中的单点失败。为了可以从这些失败中幸存,session必须用来重放在失败点接收有疑问的命令。Session 层提供必要的工具来标识有疑问的命令集,而且在无重复递交风险的状况下重放这些命令。
google group已经被屏蔽了,若是谁有兴趣的话能够到这个地址来参与amqp的讨论:http://n3.nabble.com/AMQP-f185611.html