当一个节点发送像这样的方法帧时,它总是会遵循一个内容头帧(conent header frame)和零个或多个内容体帧(content body frame)的形式.
当一个节点发送像这样的方法帧时,它总是会遵循一个内容头帧(conent header frame)和零个或多个内容体帧(content body frame)的形式.
一个内容头帧有下面的格式:
我们将内容体放置在不同的帧中(并不包含在方法中),因此AMQP可支持零拷贝技术,这样其内容就不需要编组或编码. 我们将内容属性安放在它们自己的帧中,以便收件人可以有选择地丢弃他们不想处理的内容。
2.3.5.3 心跳帧
心跳是一种设计用来撤销(undo)TCP/IP功能的技术,也就是说在长时间超时后,它有能力通过关闭broker物理连接来进行恢复.在某些情景下,我们需要快速知道节点连接是否断开了,或者是由于什么原因不能响应了.因为心跳可以在较低水平上进行,我们在传输层次上按节点交换的特定帧类型来处理,而不是按类方法.
2.3.6 错误处理
AMQP使用异常来处理错误.任何操作错误(未找到消息队列,访问权限不足)都会导致一个通道异常. 任何结构化的错误(无效参数,坏序列的方法.)都会导致一个连接异常.异常会关闭通道或连接,同时也会向客户端应用返回响应码和响应文本.我们使用了类似于HTTP等协议和其它大多数协议中的三位回复代码和文字回复文本方案.
2.3.7 关闭通道和连接
连接或通道,对于客户端来说,当其发送Open时则被认为是“打开”的,对于服务器端来说,当其发送Open-Ok时则被认为是打开的。基于这一点,一个希望关闭通道或连接的对等体也必须使用握手协议来这样做。
可出于任何原因,可能会正常地或异常地关闭一个通道或连接-因此必须仔细小心。
对于突然或意外关闭,并不能得到快速探测,因此当发生异常时,我们可能会丢失错误回复代码。
正确的设计是对于所有关闭必须进行握手,使我们关闭后对方知道相应的情况。
当一个节点决定关闭一个通道或连接时,它发送一个Close方法。接收节点必须使用Close-Ok来响应Close,然后双方可以关闭他们的通道或连接。请注意,如果节点忽略了关闭,当两个节点同时发送Close时,可能会发生死锁。
2.4 AMQP Client 架构
可直接从应用程序中读写AMQP帧,但这是相当糟糕的设计.
即使是最简单的对话框也比较复杂(比如同HTTP比较),应用程序开发者没必要为了向消息队列发送消息, 而来理解二进制这样的东西. 推荐的AMQP client架构须由下面的多个抽象层组成:
1. 帧层. 此层接受AMQP协议方法,并按某种语言格式(结构,类等等) 来序列化成线路级帧.帧层可以根据AMQP规范机械产生(这是在一个协议的建模语言,专为AMQP定义了XML实现).
2. 连接管理层. 此层用于读写AMQP帧,并管理所有连接,会话逻辑.在此层中,我们可以封装打开连接和会话,错误处理,内容传输和接收的全部逻辑. 此层的大部分都可通过AMQP规范来生成.例如,规范定义了哪些方法可以携带内容, 因为逻辑发送方法和可选的发送内容可以机械的生成.
3. API 层. 此层暴露了应用程序工作的特定API. API层可能会反映一些现有的标准,或暴露高层AMQP的方法,或对本节前面介绍的内容做一个映射。AMQP方法设计为使这些映射简单有用。API层本身可能是由多个层组成的,如.构建于AMQP方法API之上的高级API.
此外,通常还会有一些I / O层,这此可以是非常简单的(同步套接字读取和写入)或复杂的(完全异步多线程I / O)。此图显示了整体推荐的架构:
在本文档中,当我们说"client API"的时候,我们指的则是应用程序下的所有层(i/o,帧,连接按理和API层).我们通常将客户端API和应用程序分开说, 在这里,应用程序会使用客户端API来同中间件服务器进行对话.
3 功能说明
3.1 Server 功能说明
3.1.1 消息和内容
消息是中间件路由和队列系统处理的原子单元。消息可携带一份内容,它包括一个内容头,一组属性,和一个内容体,和持有一个不透明的二进制数据块。
一个消息可以对应到许多不同应用程序的实体:
一个应用程序级消息
一个传输文件
一个数据流帧等等.
消息可以持久化.一个持久化消息可以安全地存储在磁盘上,即使是在严重的网络故障,服务器崩溃、溢出等情况下也可确保投递.消息也可以有优先级.高优先级消息会在等待同一个消息队列时,在低优先级消息之前发送. 当消息必须被丢弃以确保服务器质量水平,将会优先丢弃低优先级消息.
服务器不能修改接收到并将传递给消费者应用程序的消息内容体. 服务器可在内容头中添加额外信息,但不能删除或修改现有信息.
3.1.2 虚拟主机(Virtual Hosts)
虚拟主机是服务器内的数据分区, 它为在共享基础设施上的管理带来了方便.
一个虚拟主机包括其命名空间,一组交换器,消息队列以及所有相关对象. 每个连接必须关联一个单个虚拟主机.
在认证后,客户端可在Connection.Open方法中选择虚拟主机. 这意味着,服务器上的认证方案可在此服务器上的所有虚拟主机上共享. 然而,对于每个虚拟主机来说,也可以独特的认证方案. 对于每个虚拟主机需要不同的身份验证方案的管理员应该使用单独的服务器。
连接中的所有通道都在同一个虚拟主机上工作.在同一个连接中,没有与不同虚拟主机通信的方式, 也没有在不断开连接重新开始的情况下,切换到其它虚拟主机的可能性.
该协议没有提供用于创建或配置虚拟主机的机制-这在服务器内是一个不确定的方式,是完全依赖于实现的。
3.1.3 交换器
交换器是一个虚拟主机内的消息路由代理。交换器实例(我们通常称之为“交换器”)接受消息和路由信息-主要是一个路由键-或者将消息传递到消息队列,或到内部服务。交换器是基于每个虚拟主机命名的。
应用程序可以在权限范围内自由地创建、共享、使用和销毁交换器实例.交换器可能是持久的、临时的或自动删除的。持久化的交换器会持续到他们被删除,临时的交换器会持续到服务器关闭。自动删除的交换器直到他们不再使用。服务器提供了一组特定的交换器类型。每个交换器类型都实现了一个特定的匹配和算法,如下一节中定义的。AMQP只要求少量的交换器类型,并推荐了一些。此外,每个服务器实现可以添加自己的交换类型。
交换器可以将单个消息并发地路由到的消息队列中。这将创建一个独立消息的多个实例。
3.1.3.1 Direct交换器类型
direct 交换器按如下方式来工作:
1. 消息队列使用路由键K来绑定交换器.
2. 发布者使用路由键R来向交换器发送消息.
3. 在K=R时,消息会传递到消息队列中.
server必须实现direct交换器,并且在每个虚拟主机中必须预定义两个direct交换器: 一个名为 amq.direct, 另一个无公共名称(为Publish方法的默认交换器).
注意,消息队列可以使用任何有效的路由键值进行绑定,但通常消息队列使用它们自己的名称作路由键来绑定.
事实上,所有消息队列必须能使用其自身队列名称作路由键自动绑定无名称的交换器上.
3.1.3.2 Fanout 交换器类型
fanout交换器类型按如下方式来工作:
1. 消息队列不使用参数来绑定交换器.
2. 发布者向交换器发送消息.
3. 消息无条件传递给消息队列。
fanout 交换器是微不足道的设计与实现.此交换器类型和预声明的交换器称为amq.fanout,它是强制的.
3.1.3.3 Topic交换器类型
topic交换器类型按如下方式来工作:
1. 消息队列使用路由模式P来绑定到交换器.
2. 发布者使用路由键R来向交换器发送消息.
3. 当R匹配P时,消息将被传递到消息队列.
用于topic交换器的路由键必须由0个或多个由点号
用于topic交换器的路由键必须由点分隔的零或多个单词组成.每个单词必须包含字母A-Z和a-z 以及数字0-9.
路由模式与路由键遵循相同的规则,* 用于匹配单个单词,# 用于匹配0个或多个单词.因此路由模式*.stock.# 会匹配路由键usd.stock 和eur.stock.db 但不匹配stock.nasdaq.
对于topic交换器我们建议的设计是保持所有已知路由键的集合,当发布者使用了新的路由键时,才更新此集合. 通过给定一个路由键来确实所有绑定是可能的,因此可为消息快速找到消息队列. 此交换器类型是可选的.
server应该实现topic交换器类型,在这种情况下,server 必须在每个虚拟主机中预先定义至少一个 topic交换器,其名称为amq.topic.
3.1.3.4 Headers交换器类型
headers交换器类型按如下方式进行工作:
1. 消息队列使用包含匹配绑定和带有默认值的header参数表来绑定交换器.在这种交换器类型中,不使用路由键.
2.发布者向交换器发送消息,这些消息的headers属性中包含名称-值对的表.
3.如果消息头属性与队列绑定的参数相匹配,则消息传递给队列。
匹配算法是由参数表中的名称值对这样的特殊绑定参数来控制的. 这个参数的名称是'x-match'.
它可以接受两种值, 以表示表格中其它的名称值对将如何来进行匹配:
'all' 则表明所有其它的名称值对必须与路由消息的头属性相匹配(即.AND匹配)
'any' 则表明只要消息头属性中的任何一个字段匹配参数表中的字段,则消息就应该被路由(即. OR匹配).
绑定参数中的字段必须与消息字段中的字段相匹配,这些情况包括:如果绑定参数中的字段没有值且在消息头中存在相同名称的字段,或者绑定参数中的字段有值,且消息属性中存在同样的字段且有相同的值。
任何以'x-'而不是'x-match'开头的字段为将来保留使用并会被忽略.
server应该实现headers交换器类型, 且server必须在每个虚拟主机中预先声明至少一个headers交换器,且名称为amq.match.
3.1.3.5 System交换器类型
system交换器类型按如下方式进行工作:
1. 发布者使用路由键S来向交换器发送消息.
2. system交换器将其传递给系统服务S.
系统服务以"amq."开头,为AMQP保留使用. 在服务器环境中,所有其它名称可自由使用. 此交换器类型是可选的.
3.1.3.6 实现定义的交换器类型
所有非规范交换器类型必须以"x-"开头. 不以"x-"开头的交换器作为将来AMQP标准保留使用.
3.1.4 消息队列
消息队列是一个名为FIFO的缓冲区且为一组消费者应用程序保存消息.
在其权限范围内,应用程序可以自由地创建、共享、使用和销毁消息队列.
注意,在一个队列中可能存在多个读者,或存在客户端事务,或存在使用了优先级字段,或存在使用了消息选择器,或特定实现了投递优化的队列可能不会真正地展现出FIFO特性. 唯一可以确保FIFO的方式是只有一个消费者连上了队列.在那些情况下,队列可描述为弱-FIFO.
消息队列可能是持久化的或自动删除的.持久化消息队列会持续到它们删除时为止. 临时消息队列可持续到服务器关闭时为止.自动删除消息队列可持续到它们不再使用时为止.
Message队列可将消息存储在内存,磁盘,或两者的组合中.消息队列是基于虚拟主机来命名的.
消息队列保存信息,并可在一个或多个消费客户端之间进行分发.路由到消息队列中的消息不能再发给多个客户端,除非在失败或拒绝后进行重发.
单个消息队列可在同个时间可独立地持有不同类型的内容.也就是,如果Basic和文件内容都发给了同一个消息队列,这些将会作为请求独立地分发给消费应用程序.
3.1.5 绑定
绑定是消息队列和交换器之间的关系.绑定特有的路由参数将告诉交换器那些队列应该得到消息. 应用程序可根据需要来驱动消息流向它们的消息队列. 绑定的寿命依赖于定义它们的消息队列 - 当消息队列被销毁时,其绑定也会被销毁.Queue.Bind 方法的特定语义将依赖于交换器类型.
3.1.6 消费者
我们使用术语"consumer"来表示应用程序和控制客户端程序来接收消息队列中的实体.当客户端启动一个消费者,它就在服务器中创建了一个消费实体 .当客户端退出一个消费者时,它就销毁了一个服务器中的消费者实体. 属于单个客户端通道的消费者可异步地将消息发送到队列中.
3.1.7 服务质量
服务质量控制了消息发送的速度. 服务质量依赖于被分发的内容类型.一般的服务质量,在客户端应答消息前,会使用预提取的概念来指定发送多少个消息或多少个字节的数量. 目标是提前发送消息数据,以减少延迟。
3.1.8 确认/应答
应答是从客户端程序发出的正式信号,用以表示消息队列中的消息已经得到成功处理. 有两种应答模型:
1. 自动地(Automatic), 在这种情况下,只要消息投递到了应用程序,服务器就会立即从消息队列中删除消息(通过 Deliver 或 Get-Ok 方法).
2. 明确地(Explicit),在这种情况下,客户端程序必须对每个消息发磅一个Ack方法以表示消息被处理了.客户端层可以不同方式来实现明确应答,如.只要收到了消息或当应用程序表示消息已经处理了.
这些区别不会影响AMQP或互操作性.
3.1.9 流控制(Flow Control)
流控制是一个用来中止节点消息流的紧急过程. 它在客户端和服务器端都按同样方式工作,且都是由Channel.Flow命令实现的. 流控制是唯一可以阻止一个过度生产发布者的机制.如果它使用消息确认(这通常意味着使用事务), 消费者则可以使用更优雅的预取机制窗口。
3.1.10 命名约定
这些约定规范了AMQP实体命名. 服务器和客户端必须遵守这些约定:
用户定义的交换器类型前辍必须是"x-"
标准交换器实例前辍是"amq."
标准系统服务前辍是"amq."
标准消息队列前辍是"amq."
所有其他的交换器、系统服务和消息队列名称都在应用程序空间中。
3.2 AMQP 命令说明(Classes & Methods)
3.2.1 解释性注释
出于互操作原因,AMQP方法可以定义特定的最小值(如每消息队列的消费者数量)。这些极小值被定义在每个类的描述中。
遵从AMQP的实现应该为这些字段实现合理值, 最小值只用在最小能力的平台上.
语法使用这样的标记法:
'S:' 指示从服务器发送到客户端的数据或方法;
'C:' 指示从客户端发送到服务器的数据或方法;
+term or +(...) 表达式表示1个或多个实例;
*term or *(...) 表达式表示0个或多个实例.
我们定义的方法是:
一个同步请求("syn request").发送节点应该等待特定的回复方法,但可以异步实现此方法;
一个同步回复("syn reply for XYZ");
一个异步请求或答复 ("async").
3.2.2 类和方法细节
这部分是由生成的文件amqp-xml-spec.odt提供。
4 技术说明
4.1 IANA分配的端口号
IANA为标准AMQP的TCP和UDP分配了5672端口。UDP端口被保留用于将来的组播实现。
4.2 AMQP 线程级格式
4.2.1 正式协议语法
我们为AMQP提供了一个完整语法(这只是AMQP提供的参考,跳到下一节,你会发现不同的帧类型和格式):
我们使用了IETF RFC 2234中定义的增强BNF语法. 总体而言,
规则的名称仅仅是名称本身。
终端是由一个或多个数字字符指定的,这些字符的基本解释为“d”或“x”。
通过列出一系列规则名称,一个规则可以定义一个简单的,有序的字符串的值.
其他数值的范围可以简洁指定,使用破折号(“-”)来表示替代值的范围。
在圆括号中的元素被视为单个元素,其内容是严格有序的。
由/分隔的元素是可替代值.
元素之间的操作符 "*"表示重复.完整格式为: "<a>*<b>element",这里<a>的<b>是可选的十进制值, 表示只能出现大于<a>而小于<b>的元素.
规则形式: "<n>element" 等价于<n>*<n>element.
方括号中的元素是可选元素.
4.2.2 协议头
client必须通常发送一个协议头开始新连接.它是8字节序列:
协议头由大写字母"AMQP",其后跟常量%d0组成:
1. 协议主版本号, 按照章节1.4.2中描述的使用.
2. 协议次版本号, 按照章节1.4.2中描述的使用.
3. 协议修订版本, 按照章节1.4.2中描述的使用.
该协议协商模型与现有HTTP协议兼容,使用常量文本字符串来发起连接, 并使用防火墙来检测协议的开始以决定应用什么规则.
client和服务通过以下方式来达成协议版本一致:
client打开一个到AMQP服务器的新socket连接,并发送协议头.
server可接受或拒绝协议头.如果它拒绝了协议头,它将会输出一个有效的协议头到socket,然后再关闭socket.
否则它会同意(leaves)socket打开,并相应地实现协议.
示例:
实现者指导方针:
server可接受非AMQP协议,如HTTP.
如果server无法识别socket数据中的前5个字节,或者它不支持client请求的协议版本,它必须输出一个有效的协议头到socket,然后再关闭socket (必须确保client应用程序能收到数据) ,最后再关闭socket连接.服务器可以打印诊断信息以辅助调试。
client可使用服务器支持的最高版本来进行检测,如果收到了服务器发回的这种信息,就可使用较低版本来进行重连
实现了多版本AMQ的Clients和servers都应该使用8字节的协议头来标识协议.
4.2.3 通用帧格式
所有帧都以7个字节的头开始,其中包括一个type字段 ,一个channel字段和一个size字段:
AMQP 定义了如下的帧类型:
Type = 1, "METHOD": 方法帧
Type = 2, "HEADER": 内容头帧
Type = 3, "BODY": 内容体帧.
Type = 4, "HEARTBEAT": 心跳帧.
通道编号为0的代表全局连接中的所有帧,1-65535代表特定通道的帧.
size字段是负载的大小,不包括结束帧字节. 由于AMQP假设是一个可靠的连接协议,我们使用结束帧来检测错误客户端和服务器实现引起的错误.
实现者指导方针:
结束帧必须是十六进制值%xCE.
如果一个节点收到了未定义类型的帧,它必须将其视为致命的协议错误,并关闭连接,而不进一步地发送任何数据
当一个节点读取到帧时,在解码帧前,它必须检查结束帧是否是有效的. 如果结束帧无效,它必须将其视为致使的协议错误,并关闭连接,而不进一步地发送任何数据. 它应该记录相关问题的日志信息,这样就可以服务器或客户端帧代码实现中表示错误.
节点发送的帧大小不能超过约定的大小. 节点收到超过大小的帧时,必须发出一个回复码为501(帧错误)的连接异常信号.
对于所有心跳帧,方法帧,连接类的头和体,通道编号必须为0. 节点收到非0通道编号的这些帧必须使用回复码503(无效命令)来发出异常信号.
4.2.4 方法负载
方法帧的体包括一个不可变的数据字段列表,称为"arguments".所有方法体都以类型和方法的标识符开始:
实现者指导方针:
class-id 和 method-id是由AMQP类和方法定义的常量.
arguments 是特定于每个方法中的一组AMQP字段.
Class id 中%x00.01-%xEF.FF范围内的值被AMQP标准类保留使用.
Class id 中%xF0.00-%xFF.FF (%d61440-%d65535) 范围内的值可用于非标准扩展类实现.
4.2.5 AMQP 数据字段
AMQP有两种级别的数据字段:用于方法参数的原生数据字段, 以及用于多个应用之间传递数据的字段表. 字段表是原生数据字段的超集.
4.2.5.1 Integers
AMQP定义了这些原生整数类型:
无符号字节(8 bits).
无称号短整形(16 bits).
无符号长整形(32 bits).
无符号长长整形(64 bits).
整形和字符串长度总是无符号的,且按网络字节顺序保存. 当存在两个高低系统时(如.两个Intel CPUS),我们不会对它们的交互尝试优化.
实现方针:
实现不能假设帧内的整形编码在内存边界中是对齐的.
4.2.5.2 Bits
AMQP定义了一个原生位字段类型. 位累积成整个字节. 当在帧中两个或更多位相邻时,它们会被包装成一个或多个字节,且在每个字节中以低位开始.
没有要求在一个帧中的所有位必须是连续的,但这通常是做,以尽量减少帧尺寸。
4.2.5.3 Strings
AMQP 字符串是可变长度,由一个整数长度后跟零个或多个字节数据表示. AMQP定义了两种原生字符串类型:
短字符串(Short strings),以8位无称号整形长度后跟0个或多个字节数据存储. 短字符串可携带最多255字节的UTF-8数据, 但不能包含二进制零字节.
长字符串(Long strings), 以32位无称号整形长度后跟0个或多个字节数据存储. 长字符串可包含任意数据.
4.2.5.4 时间戳(Timestamps)
时间戳是以精度为1秒的64位POSIX time_t 格式保存的.使用64伴可以避免31位和32位相关的time_t值概括问题(wraparound issues).
4.2.5.5 字段表
字段表是包含名称-值对的长字符串. 名称-值对编码为:以短字符串定义名称,字节定义值类型和值. 有效的表字段类型是原生整形,位,字符串,时间戳类型的扩展. 多字节整形字段通常是按网络字节顺序保存的.
指导方针:
字段名称必须以字母开头,其后可跟'$,'#',数字,下划线,最大长度为128个字符.
server应该验证字段名称,如果收到了无效的字段名称,它应该使用回复码503(语法错误)来发出异常信号.
十进制值不用于支持浮点值,它是固定的业务值,如货币汇率和金额。其字节编码代表了位置编号,其后跟着一个无符号的长整数.“十进制”是无符号的.
重复字段是非法的。对于一个包含重复字段的表,其行为是未定义的。
4.2.6 内容帧
某些特定的方法(Publish, Deliver, etc.) 会携带内容.请参考 "Functional Specifications" 来了解每种方法的说明,以及它们是否是携带内容的方法.
内容由1个或多个帧组成:
1. 只有一个内容头帧能提供内容属性.
2. 可选的, 可以有1个或多个内容体帧.
特定通道上的内容帧是严格有序的. 也就是说,它们可以和其它通道的帧混合,但同一个通道内两个帧是不可能混合或重叠, 也不可能出现单个内容上的内容帧与相同通道上的方法帧相混合.
注意,任何非内容帧都会明确地标识内容的结束. 尽管可从内容头中知道内容的大小,但也允许发送者在不关闭通道的情况下中止内容发送.
实现者指导方针:
收到不完整或错误格式内容的节点必须使用回复码500(非希望帧)抛出一个连接异常. 这包括缺少内容头,内容头中错误的class IDs,缺少内容体帧等等.
4.2.6.1 内容头
内容头负载有下面的格式:
实现者指导方针:
class-id必须与方法帧class id匹配. 节点必须对无效的class-id使用501回复码(帧错误)抛出一个连接异常.
weight字段未使用且必须是0.
body大小是一个64位值,它定义了内容体的总大小,也就是后面内容体帧的body大小的总和. 0表示无内容体帧.
property flags是位数组,它表示每个属性的存在性. 位是从最高到最低进行排序的,位15代表第一个属性.
property flags可指定多于16属性.如果最后位(0)被设置了,这表明其后有进一步的属性标志字段。根据需要,这里有许多属性标志字段。
属性值是特定类的AMQP数据字段.
位属性仅由它们各自的属性标志(0或1)表示,并且在属性列表中不存在。
内容帧中的通道编码不能为0.在内容帧中收到0通道编号的节点必须使用504回复码(通道错误)来发出异常信号
4.2.6.2 内容体
内容体负载是是不透明的二进制块,其后跟着一个结束帧字节:
内容体可以根据需要分成多个帧.帧负载的最大大小可在连接时,由两端进行协商.
实现者指导方针:
节点必须要能将分成多个帧的内容体作为单一集合进行存储处理,要么分成更小的帧重新传输,要么 连接成单个块分发给应用程序.
4.2.7 心跳帧
心跳帧告诉收件人发件人仍然是活的. 在连接时,心跳帧的速率和时间都可以调整.
实现者指导方针:
心跳帧的通道编号必须为0. 收到无效心跳帧的节点需使用501回复码(帧错误)来抛出异常.
如果节点不支持心跳,它必须在不发出错误或失败信号的情况下丢弃心跳帧.
client收到Connection.Tune方法后,必须要开始发送心跳, 并在收到Connection.Open后,必须要开始监控.server在收到Connection.Tune-Ok后,需要开始发送和监控心跳.
节点应该尽最大努力按固定频率来发送心跳. 心跳可在任何时候发送. 任何发送字节都可作为心跳的有效替代,因此当超过固定频率还没有发送非AMQP心跳时,必须发送心跳.如果节点在两个心跳间隔或更长时间内,未探测到传入的心跳,它可在不遵循Connection.Close/Close-Ok握手的情况下,关闭连接,并记录错误信息.
心跳应该具有持续性,除非socket连接已经被关闭, 包括在Connection.Close/Close-Ok 握手期间或之后的时间.
4.3 通道复用
AMQP 允许节点创建多个独立的控制线程.每个通道都可作为共享单个socket的虚拟连接:
实现者指导方针:
AMQP节点可支持多个通道.在连接协商期间,可定义最大通道数目,节点可协商这个数值为1.
每个节点都应该以公平的方式平衡所有打开通道的流量. 这种平衡可以每帧为基础,也可以以每个通道上的总交通流量为基础. 节点不应该允许一个非常繁忙的通道让一个不太繁忙的通道饿死.
4.4 可见性保证
服务器必须确保客户端对服务器状态的观察是一致的。
下面的示例说明了在这种情况下,客户端的观察方法:
Client 1 和 Client 2 连上了同一个虚拟主机
Client 1 声明了一个队列
Client 1 收到了Declare.Ok回复 (观察”的一个例子)
Client 1 将其告知了Client 2
Client 2 对同一个队列做了被动声明
可见性必须保证Client 2能看到队列(在没有删除的情况下)
4.5 通道关闭
当发生以下事件时,server会考虑通道已经关闭了:
1. 节点关闭了通道或其父连接使用了Close/Close-Ok握手.
2. 节点在通道或父连接上抛出了异常.
3.节点未使用 Close/Close-Ok握手关闭了父连接socket.
当服务器关闭通道时,通道上任何未应答的消息将标记为重新分发.
当服务器关闭连接时,它会删除连接所拥有的自动删除信息.
4.6 内容同步
在某些情况下,同步请求响应方法会对同一个信道上的异步内容传递产生影响,包括:
Basic.Consume 和 Basic.Cancel 方法, 这些会启动和停止消息队列中的消息流.
Basic.Recover 方法,它会要求服务器重新分发消息到通道.
Queue.Bind, Queue.Unbind, 和Queue.Purge 方法, 它会影响消息进入消息队列.
实现者指导方针:
请求-响应效果在response方法之前必须不可见,但在之后必须可见.
4.7 内容排序保证
流经通道的方法顺序是稳定的:方法按发送时的顺序接收. 这是由AMQP使用的TCP/IP传输所保证的.
此外,服务器也会按一种稳定的方式来处理内容.尤其是,经过服务器中单个路径的内容会保持顺序.
对于设定了优先级并经过单个路径内容,我们定义了一个内容处理路径-由一个传入通道,一个交换器,一个队列和一个传出通道组成.
实现者指导方针:
server必须保持流经单个内容处理路径上的顺序性,除非在Basic.Deliver或Basic.Get-Ok方法上设置了redelivered字段,可根据条件规则来设置字段.
4.8 错误处理
4.8.1 异常
使用标准的异常编程模型, AMQP不会发出成功信号,只在失败时才发出信号. AMQP定义了两种异常级别:
1. 通道异常.指那些关闭通道引起的错误.通道异常通常是因为软错误引起的,这些错误并不影响应用程序的其它部分.
2. 连接异常. 这些关闭socket连接的异常通常是因为硬错误造成的,如程序错误,错误配置或其他需要干预的情况。
4.8.2 回复代码格式
AMQP 回复代码按照 IETF RFC 2821的回复代码的严重程度和理论进行定义.
4.9 限制
AMQP规范为将来的AMQP扩展或同种线路级格式使用了如下限制:
每个连接上的通道数量: 16位通道数量.
协议类数量: 16位class id.
每个协议内的方法数量: 16位 method id.
AMQP规范对于数据做了如下限制:
短字符串的最大长度为: 255字节.
长字符串或字段表的最大长度: 32位大小.
帧负载的最大大小: 32位大小
内容的最大长度: 64位大小.
服务器或客户端也可以对资源施加自己的限制,如并发连接的数量、每个通道的消费者数量、队列的数量等。这些不影响互操作性,因此并没有指定。
4.10 安全
4.10.1 目标和原则
为了防止缓冲区溢出,我们在所有地方都使用特定长度的缓冲区. 当读取数据时,所有数据都可以使用允许的最大长度来进行验证.无效的数据可以被明确地处理,通过关闭通道或连接。
4.10.2 拒绝服务攻击
AMQP 通过回复码并关闭通道或连接来处理错误.这避免了错误出现后的模糊状态.在连接协商期间,服务器可假设特殊条件是因获取访问服务器的敌对尝试所造成的.对于连接协商中的任何异常,一般处理是暂停该连接 (可能是一个线程)几秒种时间,然后再关闭网络连接. 这包括语法错误,过大数据,或认证失败.服务器应该记录所有这些异常标志或阻止客户端挑起多个故障.