消息中间件 一 之 AMQP译文

RabbitMQ是AMQP的实现成果, 所以在研究RabbitMQ之前, 不如先看看协议本身.

1 Overview 概述

1.1 Goals of This Document 文档目标

本文档定义了网络协议AMQP, 客户端可以使用该协议与消息中间件服务器进行通信. 我们面向的是在本领域有一定经验的技术人员, 我们会提供充分的文档, 工程师可以通过这些文档使用任何高级语言或者硬件平台构建解决方案.

1.2 Summary 概述

1.2.1 Why AMQP 为什么用AMQP

AMQP提供了完整的方法支持客户端和消息中间件服务器之间通信的操作. 我们希望开发和使用都使用标准化的消息中间件技术, 这样会降低企业的花销和系统集成的成本, 而且会为大众提供一个企业级的集成服务. 我们的目标是通过AMQP消息中间件可以驱动网络本身, 而且通过消息中间件可以开发出新的有用的应用.

1.2.2 Scope of AMQP

为了完成一个完整功能的消息中间件需要两方面的支持, 详细的网络协议和服务端服务.
因此AMQP在这两方面做了如下定义:
1 AMQ模型是定义的一套消息处理操作, 它包含了一套在服务端处理消息路由和消息存储的组件, 以及关联这些组件的规则.
2 AMQP是一个wire-level(?)的网络协议, 它允许客户端应用和服务端进行通信, 而且可以通过自己实现的AMQ模型进行交互.

虽然通过AMQP可以大概推断出服务端的消息操作, 但是我们认为对服务端有个详细的讲解有助于理解协议.

1.2.3 The Advanced Message Queuing Model (AMQ model)

我们定义了一些服务端的名词, 因为这些操作在任何服务端实现中都应该表现的一样, 因此在AMQ模型中定义了一些列组件以及这些组件如何关联的标准规则. 下面是三个重要的组件, 他们贯穿服务端整个执行过程.
1 exchange, 它接收来自生产者应用的信息, 而且通过一些特定的条件路由信息到Message queues, 这些条件通常是信息的属性或者信息的内容.
2 message queue, 它会一直存储信息, 直到消息被一个或多个消费者应用安全的使用后才会删除该信息.
3 binding, 它定义了exchangemessage queue之间的关系, 也就是提供上面提到的路由规则

使用AMQ模型我们可以简单模拟传统的面向消息的中间件概念, 比如存储转发队列和主题订阅. 当然我们也可以描述一些更难的概念, 比如基于内容的路由, 工作负载分发, 根据需求改变的消息队列. 笼统的说, AMQP服务器就像是一个邮件服务器, exchange就像是邮件发送代理, message queue就像是邮箱. binding就是发送代理中的路由表. 发布者发送信息给一个特定的代理, 代理会路由该信息到邮箱. 与AMQP相比, 之前的中间件都是发送者之间发送信息到邮箱(存储转发队列), 或者是邮件列表(主题订阅).

这个区别就在于绑定exchangemessage queue的规则是由工程师规定的而不是集成在代码中的, 这样的话我们就有可能做一些有趣的事, 比如定义这样的规则: 复制所有包含某某消息头的消息到某个message queue. AMQ模型的设计依据以下几个需求:
1 支持主流消息产品中的一些名词概念
2 提供和主流信息产品相当的性能
3 允许应用程序通过协议对服务端的特定组件进行编程
4 灵活, 扩展性, 简单

1.2.4 The Advanced Message Queuing Protocol (AMQP)

AMQP协议是一个有现代特性的二进制协议: 多通道, negotiated, 异步, 安全, 可移植, neutral, 高效. AMQP被有效的分为两层:
消息中间件 一 之 AMQP译文

功能层定义了一套命令(通过功能逻辑分类), 这些命令可以表示客户端应用的操作.
传输层负责客户端到服务端的方法执行, 信道的多路复用, framing(?), 内容编码, 心跳操作, 数据展示, 错误处理. 我们可以在不改变协议的应用层(就是应用可见的部分)的情况下替换任意的传输层. 我们也可以为不同的高级协议使用相同的传输层.
所以AMQ模型需要满足下面的需求:
1 保证一致性实现下的操作性
2 提供明确的服务质量控制
3 命名显式而且一致
4 允许通过协议完成服务器连接的配置
5 使用容易映射应用级api的命令
6 为了清晰, 每个操作只做一件事.

AMQP传输层的设计依赖下面的需求, 不分先后:
1 为了信息紧凑, 使用二进制编码, 这样打包拆包很快.
2 不限制信息长度
3 在一个连接上实现多个通道
4 长连接, 不需要特殊内部限制
5 允许在管道内使用异步命令
6 扩展方便
7 向前兼容
8 可补偿的, 通过使用强断言模型(?)
9 对编程语言采取中立态度
10 适应代码发展过程(?)

1.2.5 Scales of Deployment 部署规模

AMQP使用场景包含了不同的规模, 大体如下:
1 开发者使用: 1个服务端, 1个用户, 10个消息队列, 每秒一条信息.
2 产品应用: 2个服务端, 10-100用户, 10-50个消息队列, 每秒十条信息(每小时36K条信息)
3 部门关键应用: 4个服务端, 100-500用户, 50-100个消息队列, 每秒100条信息(每小时360K条信息)
4 地区关键应用: 略
5 全球关键应用: 略
6 市场数据(交易): 略
与容量一样, 信息的延迟也是非常重要的. 比如市场数据很快就会没有用. 所以我们可以在遵从规范的前提下提供不同的服务质量.

1.2.6 Functional Scope

我们希望提供一种多样化的信息架构
1 多对一的存储转发
2 多对多的工作负载分发
3 多对多的发布订阅
4 多对多的基于内容路由
5 多对多的文件传输
6 两个终端的点对点连接
7 大数据分布式下的多对多

1.3 Organisation of This Document 文档的组织结构

文档分为五章, 大部分是比较独立的, 你可以阅读自己感兴趣的部分:
1 overview(本章). 就是个介绍
2 General Architecture, 这章我们是描述了整体架构和AMQP的整体设计. 我们希望通过这章可以让工程师知道AMQP是如何工作的.
3 Functional Specifications, 这章我们定义了应用是如何使用AMQP的. 这章在每一个协议命令后会有一个小讨论来作为一种实现例子. 阅读这章之前需要阅读前一章.
4 Technical Specifications, 这章我们讲了AMQP的传输层是如何工作的.

1.4 Conventions 约定

1.4.1 Guidelines for Implementers 参考

 We use the terms MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY as defined by IETF RFC 2119.
 We use the term “the server” when discussing the specific behaviour required of a conforming AMQP server.
 We use the term “the client” when discussing the specific behaviour required of a conforming AMQP client.
 We use the term “the peer” to mean “the server or the client”.
 All numeric values are decimal unless otherwise indicated.
 Protocol constants are shown as upper-case names. AMQP implementations SHOULD use these names when defining and using constants in source code and documentation.
 Property names, method arguments, and frame fields are shown as lower-case names. AMQP implementations SHOULD use these names consistently in source code and documentation.
 Strings in AMQP are case-sensitive. For example, “amq.Direct” specifies a different exchange from “amq.direct”.

1.4.2 Version Numbering 版本

The AMQP version is expressed using two or three digits – the major number, the minor number and an optional revision number. By convention, the version is expressed as major-minor[-revision] or major.minor[.revision]:
 The major, minor, and revision numbers can take any value from 0 to 99 for official specifications.
 Major, minor, and revision numbers of 100 and above are reserved for internal testing and development
purposes.
 Version numbers indicate syntactic and semantic interoperability.
 Version 0-9-1 is represented as major = 0, minor = 9, revision = 1.
 Version 1.1 would be represented as major = 1, minor = 1, revision = 0. Writing “AMQP/1.1” is equivalent to writing “AMQP/1.1.0” or AMQP/1-1-0.

1.4.3 Technical Terminology 技术术语

These terms have special significance within the context of this document:
 AMQP command architecture: An encoded wire-level protocol command which executes actions on the state of the AMQ model Architecture.
 AMQ model architecture: A logical framework representing the key entities and semantics which must be made available by an AMQP compliant server implementation, such that the server state can be manipulated by a client in order to achieve the semantics defined in this specification.
 Connection: A network connection, e.g. a TCP/IP socket connection.
 Channel: A bi-directional stream of communications between two AMQP peers. Channels are
multiplexed so that a single network connection can carry multiple channels.
 Client: The initiator of an AMQP connection or channel. AMQP is not symmetrical. Clients produce and consume messages while servers queue and route messages.
 Server: The process that accepts client connections and implements the AMQP message queueing and routing functions. Also known as “broker”.
 Peer: Either party in an AMQP connection. An AMQP connection involves exactly two peers (one is the client, one is the server).
 Frame: A formally-defined package of connection data. Frames are always written and read contiguously - as a single unit - on the connection.
 Protocol class: A collection of AMQP commands (also known as Methods) that deal with a specific type of functionality.
 Method: A specific type of AMQP command frame that passes instructions from one peer to the other.
 Content: Application data passed from client to server and from server to client. The term is
synonymous with “message”.
 Content header: A specific type of frame that describes a content’s properties.
 Content body: A specific type of frame that contains raw application data. Content body frames are entirely opaque - the server does not examine or modify these in any way.
 Message: Synonymous with “content”.
 Exchange: The entity within the server which receives messages from producer applications and
optionally routes these to message queues within the server.
 Exchange type: The algorithm and implementation of a particular model of exchange. In contrast to the “exchange instance”, which is the entity that receives and routes messages within the server.
 Message queue: A named entity that holds messages and forwards them to consumer applications.
 Binding: An entity that creates a relationship between a message queue and an exchange.
 Routing key: A virtual address that an exchange may use to decide how to route a specific message.
 Durable: A server resource that survives a server restart.
 Transient: A server resource or message that is wiped or reset after a server restart.
 Persistent: A message that the server holds on reliable disk storage and MUST NOT lose after a
server restart.
 Consumer: A client application that requests messages from a message queue.
 Producer: A client application that publishes messages to an exchange.
 Virtual host: A collection of exchanges, message queues and associated objects. Virtual hosts are independent server domains that share a common authentication and encryption environment.
 Assertion: A condition that must be true for processing to continue.
 Exception: A failed assertion, handled by closing either the Channel or the Connection.
These terms have no special significance within the context of AMQP:
 Topic: Usually a means of distributing messages; AMQP implements topics using one or more types of exchange.
 Subscription: Usually a request to receive data from topics; AMQP implements subscriptions as message queues and bindings.
 Service: Usually synonymous with server. AMQP uses “server” to conform with IETF standard nomenclature.
 Broker: synonymous with server. AMQP uses the terms “client” and “server” to conform with IETF standard nomenclature.
 Router: Sometimes used to describe the actions of an exchange. Exchanges can also act as message end-points, and “router” has special significance in the network domain, so AMQP does not use it.

2 General Architecture 整体架构

2.1 AMQ Model Architecture AMQ模型架构

This section explains the server semantics that must be standardised in order to guarantee interoperability between AMQP implementations.

2.1.1 Main Entities 主要组件

下面这张图展示了AMQ模型的整体结构
消息中间件 一 之 AMQP译文
我们可以总结下一个中间件服务器是什么: 中间件服务器是一个数据服务器, 它接收信息而且只对信息主要做两件事, 一是通过特定的条件将信息路由给不同的消费者, 二是当消费者没有办法马上接收信息的时候中间件缓存信息到内存或者硬盘.
之前的中间件服务器通常是通过一个完整的引擎实现各种特定的路由和存储. AMQ模型将实现划分为更小的模块化的, 然后以更多样化更强健的方式实现. 首先会将以上任务划分为两个截然不同的角色:
1 exchange, 从生产者接收信息, 并路由信息到message queue
2 message queue, 存储信息并转发信息给消费者.

后面我们会介绍. AMQP提供了运行期的编程能力, 主要通过以下两个发面实现:
1 在运行期通过协议创建任意的exchangemessage queue
2 在运行期通过协议绑定exchangemessage queue以此创建任意的消息处理系统.

2.1.1.1 The Message Queue 信息队列

消息队列可以存储信息到内存或者硬盘, 然后按一定顺序分发信息给一个或多个消费者. 消息队列就是消息的存储和分发组件. 每个消息队列是完全独立的, 而且相当智能. 消息队列有很多属性: 私有的或者共享的, 持久的或者临时的, 客户端命名的或者服务端命名的等等. 通过选择适当的属性, 我们可以使用消息队列实现传统中间件功能, 比如:
1 一个共享的存储转发队列, 用来保存信息和按照轮询的方式分发信息给消费者. 存储转发队列通常是持久化队列, 而且是在多个消费者间共享的.
2 一个私有应答(?)队列, 只存储和发送信息给一个消费者. 应答队列通常是临时的, 由服务端命名的, 而且是消费者私有的队列.
3 一个私有的订阅队列, 会通过订阅信息收集信息, 然后分发这些信息给唯一的消费者. 订阅队列农场是临时的, 由服务端命名的, 而且是消费者私有的.
这些条目没有在AMQP中正式定义: 它们只是告诉我们如何使用消息队列的例子. 所以像创建一个持久的共享的订阅队列这种操作是非常容易的.

2.1.1.2 The Exchange 交换机(太难听, 后面就直接用exchange)

exchange会接收生产者发送的信息, 然后根据事先排列好的条件路由信息到不同信息队列. 这些条件叫做bindings. exchange是绑定和路由引擎. 也就是说exchange会检查信息, 然后使用自己的绑定表来决定怎么发送信息给消息队列或者其他的exchange. exchange绝对不会存储信息. exchange这个词既是指一类算法也是指这类算法的实例. 为了更恰当, 我们使用exchange类型和exchange实例.
AMQP定义了一系列标准exchange类型, 这些类型覆盖了基本的路由分发信息所需要的类型. AMQP服务器会默认提供这些类型对应的exchange实例. 应用端在使用AMQP中可以额外创建自己的exchange实例. exchange类型需要命名以便应用可以使用他们自己创建的exchange类型. 同样exchange实例也需要命名, 这样应用才知道怎么去绑定队列和发布者消息.

2.1.1.3 The Routing Key

通常情况下, exchange会检查信息属性, 它的头信息和内容信息, 使用这些信息和其他合理信息来决定如何路由这条信息.
在大多数简单情况下, exchange只检查信息的一个被叫做routing key的字段. routing key是exchange可以用来决定如何路由信息的虚拟地址.
对于点对点路由, routing key通常是信息队列的名称. 对于发布订阅路由, routing key通常是一个有层级结构的主题值.
在更复杂的情况下, routing key可能要结合信息的头信息或者内容信息.

2.1.1.4 Analogy to Email 类比邮箱系统

类比邮箱系统来看AMQP中的概念, 我们会发现这些概念并不是很新奇.
1 AMQP信息与邮件信息类似
2 消息队列就像是一个邮箱
3 消费者就像一个可以获取和删除邮件的邮件客户端
4 exchange就像一个MTA邮件转发代理, MTA会检查邮件而且根据routing key和路由表决定如何发送信息给一个或多个邮箱.
5 a routing key corresponds to an email To: or Cc: or Bcc: address, without the server information (routing is entirely internal to an AMQP server)?????)
6 exchange实例就像是独立的MTA进程, 它们处理一些邮件子域, 或者特殊的邮件通信类型.
7 binding就像MTA中路由表中的条目

AMQP的优势是我们可以在运行时创建消息队列, exchange, bindings, 而且我们可以编排这些组件的关系, 使得它远比只是映射到邮箱名字这样的方式复杂.
我们不应该太深入的将AMQP和邮箱类比, 它们还是有本质的区别的. 对于AMQP来说挑战是在服务器中路由和转发信息, 这种服务器按照SMTP的说法是"自主系统". 相较而言, 邮箱系统的挑战是如何在自主系统间路由信息. 在系统间和在系统中路由信息是完全不同的问题而且有不同的解决方法, 即使只是为了维护性能这样的普通问题.(这句话应该是说这么简单的问题的解决也是不一样的, 突出两个问题的不同?)
为了在不同的AMQP服务器之间路由信息, 需要构建沟通的桥梁, 也就是为了传输信息其中一个服务器需要充当其他服务器的客户端. 这种工作方式一般适合预期使用AMQP的业务类型,因为这些桥梁可能由业务流程、合同义务和安全考虑来支撑的.

2.1.2 Message Flow
This diagram shows the flow of messages through the AMQ model server:
消息中间件 一 之 AMQP译文