消息中间件 一 之 AMQP译文(下)

3 Functional Specification 功能性说明

3.1 Server Functional Specification 服务端功能性说明

3.1.1 Messages and Content 信息和内容

在中间件处理路由和队列系统中, 信息具有原子性. 信息中有一个内容, 内容包含一个内容头, 用来存储一系列属性; 还有一个内容体, 用来保存二进制数据块
信息可以对应多种不同的应用实体:
1 应用级别的信息
2 传输的文件
3 数据流中的一帧
信息可以是持久的. 持久的信息会被安全的保存在硬盘是哪个, 而且保证在出现网络问题中也可以发送信息.
信息有一个优先级. 在相同的队列中的信息, 高优先级会比低优先级的信息优先发送. 当为了保证服务质量必须要删除信息的时候, 会优先删除低优先级的信息. 服务端不能修改接收到的和发送给消费者的消息内容体. 服务端可能会在内容头中增加信息, 但是一定不会删除或者修改已经存在的内容.

3.1.2 Virtual Hosts 虚拟主机

虚拟主机是服务端用来数据区分的概念, 在一个共享的结构中, 虚拟主机也方便管理.
一个虚拟主机有自己的命名空间, 一系列exchange, 消息队列, 和所有相关的对象. 一个连接只能关联到一个虚拟主机.
客户端会在鉴权之后, 连接打开方法中选择虚拟主机. 这也说明服务端的权限系统是在所有虚拟主机间共享的. 然而, 权限系统有可能对于每个虚拟主机是唯一的. 这对于共享基础设施是非常有用的. 管理者可以使用不同的权限控制每个虚拟主机使用不同的服务器.
一个连接中的所有通道都使用一个虚拟主机, 在同一个连接中和不同的虚拟主机通信是不可能的, 在没有关掉连接重启的前提下也不可能修改连接的虚拟主机.
协议中没有提供创建或者配置虚拟主机的机制, 这些服务端以一种未定义的形式完成的, 并且完全是依赖实现的.

3.1.3 Exchanges

exchange是一个包含虚拟主机的信息路由代理. 一个exchange实例(通常我们叫做一个exchange)接收信息然后路由信息(大部分是根据routing key)要么给消息队列要么是内部的服务. exchange是在虚拟主机的基础上命名的.
应用可以在权限范围内创建, 共享, 使用, 销毁exchange.
exchange可以是持久的, 临时的, 或者自动销毁. 持久exchange会一直存在直到被删除. 临时exchange会在服务端关闭的时候删除. 自动删除exchange会在不被需要的时候删除.
服务端提供一些特殊的exchange类型. 每一种exchange类型都实现了一种特定的匹配规则和算法, 后面会介绍.
AMQP规定了一些exchange类型, 并推荐了一些. 而且, 每个服务端实现都可以增加自己的exchange类型.
一个exchange可以同时路由一条信息给多个消息队列. 这就会创建多个信息实例, 这些消息实例会被独立的消费掉.

3.1.3.1 The Direct Exchange Type 直连exchange

直连exchange类型工作方式如下:
1 一个消息队列通过routing key K 绑定一个exchange
2 发送者发送信息和routing key R给这个exchange
3 如果K = R那么信息会发送给上面的消息队列.
服务端必须实现直连exchange类型, 而且必须在每一个虚拟主机中提前声明至少两个直连exchange: 一个叫做 amq.direct, 另一个没有名字, 作为默认exchange在发布方法中使用.
注意, 信息队列可以使用任何值作为routing key, 但是大部分情况, 消息队列会使用他们的名称作为routing key.
特殊情况, 所有信息队列必须使用队列名称作为routing key自动绑定到匿名的exchange上.

3.1.3.2 The Fanout Exchange Type 广播exchange

广播exchange工作方式如下:
1 一个信息队列绑定到exchange不使用任何参数
2 一个发布者发送信息给这个exchange
3 信息会被无条件的发送给这个消息队列
广播exchange的设计和实现是非常简单的. 这种exchange类型和预先声明的叫作amq.fanout的exchange是必须要有的.

3.1.3.3 The Topic Exchange Type 主题exchange

主题exchange工作方式如下:
1 信息队列通过一个路由模板P绑定到exchange上
2 发送者发送信息到该exchange并携带routing key R.
3 如果R匹配P规则, 则发送信息到该信息队列
主题exchange的routing key必须包含0或多个单词, 由"点."分割. 每一个段子可能包含字母或者数字.
路由模板规则和routing key一致, 额外多了一些通配符, "*"匹配一个单词, “#“匹配一个或多个单词. 因此路由模板”*.stock.#“会匹配"usd.stock"和"eur.stock.db”, 但是不会匹配"stock.nasdaq”.
一个关于主题exchange设计的建议, 我们可以保存所有routing key到一个集合, 然后当发送者使用新的routing key时更新这个集合. 这样可以找到一个routing key对应的绑定, 而且可以快速的找到对应的消息队列. 主题exchange是可选的, 服务端应该事先主题exchange, 如果实现的话, 服务端必须在每个虚拟机中提前声明一个叫做"amq.topic.*"的主题exchange.

3.1.3.4 The Headers Exchange Type

header exchange工作方式如下
1 消息队列通过一个参数表绑定到exchange, 该参数表包含与该绑定匹配的头信息和可选的值. 绑定中不使用routing key.
2 发送者发送信息到exchange, exchange的头信息属性包含一个键值对的表.
3 如果头信息属性和队列信息匹配那么该信息会发送到这个队列.

3.1.3.5 The System Exchange Type 系统exchange

系统exchange工作方式如下
1 发送者发送信息给系统exchange, 包含一个routing key S
2 系统exchange发送这个信息给系统服务S
系统服务名称以"amq."开头, 这个是提供给AMQP使用的保留关键字. 其他名字服务器实现可以随便使用. 系统exchange是可选的.

3.1.3.6 Implementation-defined Exchange Types 自定义exchange

所有非标准exchange类型必须以"x-"开头. exchange类型没有"x-"开头的名称可能以后被AMQP使用.

3.1.4 Message Queues 消息队列

消息队列是一个命名的先入先出缓存队列, 它会代替一些消费者应用保存信息. 在权限范围内, 应用可以随意创建, 共享, 使用和销毁消息队列.
注意, 在某些场景下, 消息队列可能不会表现出先入先出的特性, 比如多个消费者从一个队列读取信息, 或者在客户端事务中, 或者使用优先级字段, 或者使用消息选择器, 或者对分发实现进行特殊的优化. 唯一可以保证先入先出特性是只有一个消费者绑定队列的时候. 像上面那些场景中的队列可能被描述为弱先入先出.
消息队列可以是持久的, 临时的或者自动删除的. 持久队列会一直存在直到被删除. 临时队列会在服务器关闭时删除. 自动删除队列会在不再被使用时删除.
消息队列保存信息到内存或者硬盘或者都有. 消息队列是在每个虚拟主机基础上命名的.
消息队列保存和分发信息到一个或者多个消费者. 但是消息队列中的一条信息不会发送给超过一个客户端, 除非是发生错误或者拒绝后的重发.
一个消息队列可以同时而且独立的持有不同类型的内容. 也就是说, 如果基础信息和文件信息被发送到同一个队列, 那么这些信息会被独立的发送给消费者应用.

3.1.5 Bindings

binding表示消息队列和exchange的关系. binding通过特殊的路由参数来告诉exchange哪个信息应该给哪个消息队列. 应用可以根据需要创建和销毁binding, 以此来驱动信息进入到消息队列. binding的生命周期取决于它绑定的消息队列, 当一个消息队列销毁时, 它的binding也会被销毁. Queue.Bind方法的依赖于exchange类型.

3.1.6 Consumers 消费者

我们使用"消费者"来表示客户端应用和可以控制一个客户端应用从消息队列接收信息的实体. 当客户端"启动一个消费者"就会在服务端创建一消费者实体. 当客户端"取消消费者"就会销毁服务端的消费者实体. 消费者属于一个单独的消费者通道, 这就会造成消息队列异步发送信息给客户端.

3.1.7 Quality of Service 服务性能

服务性能主要影响信息发送速度. 服务性能依赖于发送的内容类型. 通常情况下, 服务性能会使用"提前获取"原则在客户端响应信息之前指定一共有多少信息或者多少字节数据需要被发送. 整体的目标就是提前发送信息数据来减少延迟.

3.1.8 Acknowledgements 应答

应答就是从客户端应用发给消息队列的一个正式信号表示自己已经成功消费信息了. 有以下两种应答模式:
1 自动, 该模式下, 服务端会在成功发送信息给应用之后马上删除队列中的信息
2 显示的, 该模式下, 客户端必选为接收并消费的每一条或每一批信息发送应答信息.
客户端可以以不同的方式实现应答, 比如在接收信息之后发送, 或者在明确处理了信息之后. 这些方式并不会对AMQP有什么影响

3.1.9 Flow Control 流控制

流控制是用来停止从某一端来的信息流的紧急过程. 它在客户端和服务端的工作方式是一样的, 它是由Channel.Flow方法实现的. 流控制是唯一可以停止一个过度生产的生产者的机制. 如果消费者使用消息应答(通常意味着使用事务), 它可以使用更优雅的预取窗口机制(?).

3.1.10 Naming Conventions 命名原则

以下这些原则管理了AMQP的实体命名. 服务端和客户端必须最受以下原则:
1 用户定义的exchange类型的前缀必须是"x-"
2 标准的exchange实例前缀必须是"amq."
3 标准的系统服务前缀必须是"amq."
4 标准的消息队列前缀必须是"amq."
5 所有exchange, 系统服务, 消息队列的名称必须在应用空间内.

3.2 AMQP Command Specification(Classes&Methods) AMQP命令说明

3.2.1 Explanatory Notes 解释说明

AMQP方法可能为了操作原因会定义一些特殊的最小值(比如每个队列的消费者数量). 这些值会被定义在每个类中.
规范的AMQP实现应该在实现这些字段上有足够的理由设置比较大的值, 最小值只是为了满足平台的最基本的使用.
语法符号说明:
1 ‘S:’ 表示从服务端发送到客户端的数据或者方法
2 ‘C:’ 表示从客户端发送到服务端的数据或者方法
3 +实例或者+(…)表达式表示’一个或者多个实例’
4 *实例或者*(…)表达式表示’0个或者多个实例’
我们将方法定义为:
1 一个同步请求(syn request). 发送端应该等待特殊的响应方法, 但是这个等待的实现可以是异步的.
2 一个同步响应(syn reply for XYZ)
3 一个异步的请求或者响应(async)

3.2.2 Class and Method Details 类和方法细节

This section is provided by the generated document amqp-xml-spec.odt.
本章内容在"amqp-xml-spec.odt"中

4 Technical Specifications 技术说明

4.1 IANA Assigned Port Number

标准的AMQP TCP和UDP的端口都由IANA设置为5672. UDP端口是用于未来实现多址传送的.

4.2 AMQP Wire-Level Format AMQP线路层结构

4.2.1 Formal Protocol Grammar 标准协议语法

我们为AMQP提供了完整的语法(这是作为参考提供的, 你可能会发现直接进入下一节会比较有趣, 下一节会展示各种帧类型和结构的细节.)
image.png

image.png

我们使用在IETF RFC 2234定义的增强BNF语法. 总的来说:
1 规则的名称就是规则本身
2 终端是由一个或多个数字字符指定, 这些字符的基本解释为"d"或"x".(Terminals are specified by one or more numeric characters with the base interpretation of those characters indicated as ‘d’ or ‘x’)
3 规则可以通过列出规则名称的序列来定义简单和有序的字符串.
4 一个可选数字范围可以使用"-“来指定.
5 使用小括号包裹的多个元素会认为是一个元素, 而且内容是严格有序的.
6 被”/“分割的元素表示是可选元素
7 操作符”*"表示前面一个元素的副本. 完整的格式是: *, 是可选的数字, 表示元素最少出现的次数, 表示元素最多出现的次数.
8 element等价于*element
9 中括号中是可选的元素序列

4.2.2 Protocol Header 协议头

客户端在打开一个新的连接的时候必须发送一个协议头. 下面是一个8字节序列:
image.png

该协议头包含了四个大写字母"AMQP", 后面是一个十进制的0, 然后是:
1 协议主版本, 参考1.4.2章节
2 协议次版本, 参考1.4.2章节
3 协议修订版本, 参考1.4.2章节
协议的兼容模型是可以兼容HTTP协议(以常量文本初始化连接)和防火墙(根据协议决定使用什么规则)的.
客户端和服务端通过以下方式对协议和版本达成一致:
1 客户端打开一个到服务端新的socket连接, 并给服务端发送协议头.
2 服务端要么接收要么拒绝. 如果拒绝的话需要发送一个有效的协议头, 并关闭连接
3 如果接收的话, 就维持连接打开状态, 并按照协议内容继续
如图所示:
image.png

实现参考如下:
1 服务端可能会接收非AMQP协议, 比如HTTP
2 如果服务端不认识消息中的头五个字节, 或者不支持客户端请求的协议版本, 服务端此时必须返回有效的协议头, flush socket(保证客户端可以接收到信息) 然后关闭连接. 服务端可以打印一个日志有助于帮助debug.
3 客户端可以通过发送它支持的协议的最高版本给服务端来探测服务端支持的协议, 如果服务端不支持, 则使用服务端返回的低版本协议重连.
4 客户端和服务端在描述他们实现的多种AMQP协议的时候都应该使用8字节的头信息.

4.2.3 General Frame Format 通用的帧格式

所有的帧结构都是以一个7字节开头的, 其中包括一个字节类型域, 两个字节的通道域, 四个字节的长度域, 如图所示:
image.png

AMQP定义帧类型如下:
1 type = 1, 方法帧
2 type = 2, 内容头帧
3 type = 3, 内容体帧
4 type = 4, 心跳帧
通道号为0表示连接中所有全局帧都可以使用, 通道号为1-65535则需要特别指定帧.
长度域中记录的是不包括帧尾字节的负载域的长度. 虽然AMQP被认定为一个可靠的连接协议, 但是客户端或者服务端的实现错误也需要我们使用帧尾去检测.
实现的参考如下:
1 帧尾的字节必须是十六进制%xCE.
2 如果某一端接收到了一个不属于定义中的帧类型, 那么该端必须认为这是一个严重的问题, 并且在不发送任何响应的情况下关闭连接.
3 当某一端在读取帧的时候, 它一定要在解析帧之前检测帧尾的正确性. 如果帧尾是无效的, 那么该端必须认为这是一个严重的问题, 并且在不发送任何响应的情况下关闭连接. 该端应该记录这个问题的日志信息, 因为这个错误表示服务端或者客户端在编码实现上有问题.
4 一端必须不能发送超过协议规定的帧的最大长度. 如果一端接收到一个超过限制长度的帧, 那么它必须返回一个501代码表示一个连接异常.
5 对于所有心跳帧和连接类引用的方法帧, 内容头帧, 内容体帧的通道号必须是0. 如果一端接收到这些帧的通道号不为0, 那么必须返回一个503代码表示连接异常.

4.2.4 Method Payloads 方法负载

方法帧体包括一个不变的数据域, 叫做"参数". 所有方法体都是以可识别的类和方法的标识数字开头的:
image.png

实现参考:
1 类id和方法id是定义在AMQP类和方法说明中的常量
2 参数域是一系列AMQP属性, 对于每一个方法都是不一样的.
3 对AMQP标准的类, 类id的值从%x00.01-%xEF.FF是被保留的.
4 所以类id值从%xF0.00-%xEFF.FF就可以用于实现非标准的扩展类

4.2.5 AMQP Data Fields AMQP数据域

AMQP的数据字段有两个级别: 一是用于方法参数的本地数据字段, 二是在字段表中用于应用之间传递的数据字段. 字段表是本地字段的超集

4.2.5.1 Integers 整数

AMQP定义了如下的本地整数类型:
1 无符号字节(1字节)
2 无符号短整型(2字节)
3 无符号长整型(4字节)
4 无符号超长整形(8字节)
整数和字符串长度总是无符号的, 而且在网络中以字节顺序排序. 我们不会优化这种情况: 一个低效的系统同一个高效的系统通信.
实现者不能认为帧中编码后的整数在内存中是字边界对齐的(一个Word是2字节)

4.2.5.2 Bits 比特, 位

AMQP定义了bit字段类型. bit类型会使用整个字节. 当一个帧中有两个或者多个bit, 那么这些bit会被压缩成一个或多个字节. 没有规定说帧中的bit必须连续, 但是这通常是一种减小帧大小的方法.

4.2.5.3 Strings 字符串

AMQP中的字符串长度是可变的, 它是由一个整数长度再加上零或者多个字节的数据. AMQP定义了两种原生的字符串类型:
1 短字符串, 存储为一个8位的无符号整数长度再加零活多个字节数据. 短字符串可以保存最多255字节的UTF-8编码的数据, 但是可能不包含二进制零字节(?)
2 长字符串, 存储为一个32位的无符号整数长度再加零活多个字节数据. 长字符串可以包含任何数据

4.2.5.4 Timestamps 时间戳

时间戳保存为一个64位的POSIX时间格式, 精确到秒. 使用64位我们可以避免未来由于31位和32位时间格式的问题.

4.2.5.5 Field Tables 字段表

字段表示一个包含组合好的键值对的长字符串. 键值对被编码为:“键”+"值"类型+"值"本身, 其中"键"使用短字符串, "值"的类型使用字节. 对于字段表有效的字段类型是原生的整数, bit, 字符串, 时间戳, 这些在语法中有说明. 多字节的整数在网络中通常会被排序.
实现参考:
1 "键"字段必须以’KaTeX parse error: Expected 'EOF', got '#' at position 5: '或者'#̲'开头, 后面可能会跟着'’,’#’, 数字, 下划线, 最多128字符.
2 服务端应该校验"键"字段, 并在接收到无效"键"字段后返回一个503(语法错误)异常信息.
3 十进制数字类型将来不会支持单精度, 而是支持固定的业务, 比如货币汇率和金额. 这些数字被编码为: 一个字节表示数字位数, 后面是一个无符号长整形. The ‘decimals’ octet is not signed(?).
4 重复的字段是非法的. 端点是不允许在表中保存重复字段的.

4.2.6 Content Framing 内容设计

某些特殊的方法(生产, 发送等)会持有内容. 请参考"方法说明"章节, 看看哪些方法会持有内容. 携带内容的方法肯定会携带内容.
内容中会包含一个或多个帧如下:
1 确定的内容头帧, 提供内容的属性.
2 可选的, 一个或者多个内容体帧
内容帧在某一个通道内是严格有序的. 也就是说, 内容帧可能和其他通道的帧搞乱顺序, 但是同一个通道的两个帧顺序不会乱而且不会重叠, 一个内容的内容帧也不可能跟同一个通道的方法帧搞混(?有点蒙)
注意, 任何非内容帧都明确了帧内容的结尾. 但是对于发送者是可以在不关闭通道的前提下停止发送内容, 虽然在内容头中显示了内容的长度(因此也知道内容帧的数量)
实现参考:
1 一端接收到不完整或者结构有问题的内容时, 必须抛出连接异常而且返回505(不希望的结构). 错误包括丢失内容头, 内容头中错误的类id, 丢失内容体等.

4.2.6.1 The Content Header 内容头

内容头负载格式如下:
image.png

实现参考:
1 类id必须和方法帧中的类id一致. 当接收到无效的类id时必须响应异常并返回501(结构错误)
2 weight字段没有使用, 必须为0;
3 体长度是一个64位的值, 用来小时整个内容体的长度, 也就是说是后面所有的内容体帧大小的总和. 0表示没有内容体.
4 内容标识是一组bit, 标识一个有序的属性中每一个属性是否存在. bit从高到低排序, 15表示第一个属性.
5 属性标识可以超过16个. 如果最后一位bit(也就是0位)设置了属性, 那么也表名后面还会有一个属性. 这里会需要很多属性字段.
6 属性的值是AMQP中不同类的拥有的数据字段
7 bit属性仅有各自的标识表示, 并不会出现在属性列表中
8 在内容帧中通道号不能为零. 某一端接收到一个通道为零的内容帧时, 必须标记连接异常, 并返回504(通道错误).

4.2.6.2 The Content Body 内容体

内容体负载是一个可见的二进制块, 后面跟着帧的结束位:
image.png

内容体可以按需拆分为多个帧. 最大的帧负载长度是在建立连接的时候定义好的.
实现参考:
1 一端在处理一个划分为多个帧的内容体时, 要么像原来一样, 拆分为更小的帧传输, 要么拼接为一个独立的块传输给应用.

4.2.7 Heartbeat Frames 心跳帧

心跳帧的作用就是通知接收端, 发送端还活着. 心跳发送的时机和频率是在连接的时候确定的.
实现参考:
1 心跳这的通道号必须是0. 某一端接收到无效的心跳帧必须抛出连接异常, 并且返回501错误(帧错误)
2 如果某一端不支持心跳操作, 那么在当接收到心跳后必须丢弃该心跳信息, 并且不需要发出任何错误信息.
3 客户端应该在接收到Connection.Tune方法后发后发送心跳, 然后在接收到Connection.Open方法后开始监控心跳. 服务端应该在接收到Connection.Tune-Ok方法后开始发送和监控心跳.
4 每一端应该在一个特定的时间规律下尽力发送心跳. 心跳可以在任何时间发送. 任何一个字节都可以代替心跳, 所以, 只有在发送非心跳信息流量超过一个心跳周期时才会发送心跳. 如果一端检测到在两个或者更多的心跳周期中没有接收到信息, 那么该端应该在不执行Connection.Close/Close-Ok握手方法的情况下关闭连接, 并记录错误日志.
5 在连接没有关闭前需要一直发送心跳信息, 包括执行关闭连接方法时和之后.

4.3 Channel Multiplexing 通道多路复用

AMQP允许端点创建多个独立的控制线程. 每一个通道就像是一个虚拟的连接, 它们共享一个socket连接:
image.png

实现参考:
1 一个AMQP端点可以支持多个通道. 通道的最大数量是在创建连接时确定的, 端点也可以调整数量为1.
2 每一个端点应该以一种比较公平的方式平衡通道的流量. 这种平衡可以在每帧上完成或者在每个通道的流量上完成. 端点不应该允许出现一个通道非常忙以至于"饿死"一个不忙的通道.

4.4 Visibility Guarantee 可见性保证

服务端应该保证客户端可以一直观察到服务端的状态. 下面这些例子展示了客户端可以观察到服务端状态指的什么:
1 客户端1和客户端2连接到同一个虚拟主机
2 客户端1声明一个队列
3 客户端1收到创建成功的信息
4 客户端1通知客户端2关于这个队列的信息
5 客户端2被动声明一个一样的队列
可见性保证了客户端2可以看到这个队列

4.5 Channel Closure 通道关闭

服务端当碰到下面这几种情况下可以考虑关闭通道:
1 某一端执行了Close/Close-Ok握手方法来挂壁通道或者该通道所在的连接
2 某一端在通道或者该通道所在的连接上抛出异常
3 某一端在没有执行关闭方法下关闭了通道所在的连接.
当服务端关闭通道时, 该通道上任何没有确定的信息会被标记为"需要重复发送". 当服务端关闭连接时, 该连接上所有标记为自动删除的信息都会被删除.

4.6 Content Synchronisation 内容同步

在某些场景下, 同步请求-响应方法会对同一个通道下的异步内容发送有一定影响, 场景包括:
1 Basic.Consume和Basic.Cancel方法, 它们可以开始和停止消息的流动.
2 Basic.Recover方法可以请求服务端重新发送信息给通道
3 Queue.Bind, Queue.Unbind和Queue.Purge方法可以影响信息进入消息队列
参考实现:
1 上述的同步请求方法在同道造成的影响在响应方法之前必须是不可见的, 在响应方法之后必须是可见的.

4.7 Content Ordering Guarantees 内容顺序保证

通道中方法流的顺序是稳定的: 方法接收的顺序和他们被发送的顺序是一致的. 这是由AMQP所使用的TCP/IP保证的. 而且, 服务端也会以一种稳定的方式处理内容. 具体来说, 流经服务器中单一路径的内容会保持顺序. 对於单一路径中不同的优先级内容, 我们定义了一个内容处理路径, 该路径包括一个进消息的通道, 一个exchange, 一个队列, 一个出消息的通道.
实现参考:
1 服务端必须保持进入单一内容处理路径的内容顺序, 除非根据规定在Basic.Deliver方法或者Basic.Get-Ok方法中设置了"重发"字段.

4.8 Error Handling 错误处理

4.8.1 Exceptions 异常

使用标准的异常程序模型, AMQP不会报告成功, 只会报告失败. AMQP定义以下两个异常级别:
1 通道异常. 该异常会关闭引起该异常的通道. 通道异常通常是由于"软"错误引起的, 这些错误一般不会影响剩余的应用.
2 连接异常. 这些异常会关闭socket连接, 而且这些异常通常是由于"硬"错误导致的, "硬"错误可以是程序错误, 配置错误或者其他需要人为接入的问题.
我们会在每个类和方法中规范的记录这些异常.

4.8.2 Reply Code Format 响应码格式

AMQP响应码遵守IETF RFC 2821中"响应码规定和原理"的定义.

4.9 Limitations 限制

AMQP说明中对为了AMQP的扩展或者同级别的协议增加了以下限制:
1 每个连接中通道的数量: 16位的通道编码(所以数量也限制了)
2 协议中的类数量: 16位的类id(同上)
3 每个协议类中方法的数量: 16位方法id(同上).
在数据方面的限制:
1 短字符串最大长度: 255个字节
2 一个长字符串或者表字段的最大长度为32位
3 一个帧负载的最大长度为32位
4 一个内容的最大长度为64位
服务端或者客户端也可以对一些资源做出限制, 比如同时可以建立连接的数量, 每个通道消费者的数量, 队列的数量等. 这些不会影响操作而且也没有详细的规定.

4.10 Security 安全性

4.10.1 Goals and Principles 目标和原则

我们为了防止缓存溢出的情况, 我们在所有场景都使用特定长度的缓存. 所有外部提供的数据在被读取的时候都会检测是否超过了允许的最大值. 无效的数据会被马上处理, 通过关闭通道或者连接.

4.10.2 Denial of Service Attacks 拒绝服务攻击

AMQP通过返回一个错误码和关闭通道或者连接来处理错误. 这避免了错误之后不确定的状态的发生. 服务端应该考虑在连接建立阶段由于非法连接尝试进入服务端引起的异常情况. 通常对于任何异常情况的响应在连接中的定义为: 暂停连接(可能是一个线程)一段时间, 然后关闭网络连接. 这些异常包括语法错误, 数据超长, 鉴权失败等. 服务端应该记录所有这样的异常而且标志或者阻止客户端引起更多的错误.

以上为AMQP协议全篇译文, 下一篇我们会根据协议内容实现一个简易RabbitMQ的客户端(当然会参考RabbitMQ客户端源码~)

发布了28 篇原创文章 · 获赞 9 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章