AMQP 0-9-1

AMQP 0-9-1 Model Explained读后感.
之前对AMQP的很多概念比较模糊,直到读了RabbitMQ主页上这篇关于AMQP 0-9-1的文章,感觉清晰了很多.

一些总结

关于持久化

和持久化有关的有好几个对象:

  • 交换机
  • 队列
  • 消息

应用程序一般会在启动时去声明交换机,启动后就认为交换机总是存在的,然而应用程序并不知道Broker重启了,这就导致期望使用的交换机不存在的情况.

正常情况下,用MQ传递业务数据肯定是希望Broker上的消息不会丢失,要达到这个目的,消息本身以及消息所处的队列都要有持久化能力.

High-level Overview of AMQP 0-9-1 and the AMQP Model

AMQP指高级消息队列协议(Advanced Message Queuing Protocol),0-9-1是这个协议的版本号.AMQP扮演的角色跟HTTP协议类似.

AMQP 0-9-1模型简介

这是文档中描述AMQP 0-9-1模型的图片
hello-world-example-routing.png

有三种参与者:

  • publisher : 消息发布者
  • Borker : 消息代理,就是中间那个方框,它包含交换机(Exchange)和队列(Queue).
  • Consumer: 消息消费者

publisher的接头人是交换机,Consumer的接头人是队列.消息由交换机分发到队列的过程称为消息路由.

publisher在发消息的时候可以指定一些附加属性(message meta-data),一部分附加属性会被Broker识别并处理,剩下的都会传递给接受消息的应用程序.

AMQP有一套消息确认机制来应对由于网络传输的不可靠性,Broker把消息投递给Consumer后,Consumer要给Broker一个确认(ACK),表示消息已经妥善处理了.消息确认机制打开后,Broker在收到ACK之前不会从队列中删除消息.

队列(Queue),交换机(Exchange)和绑定(Bindings)统称为AMQP实体(entity).

The routing algorithm used depends on the exchange type and rules called bindings.
绑定是指队列交换机之间的路由算法.

Exchanges and Exchange Types

交换机类型有四种:

  • 直连交换机(Direct exchange) : 默认的预申明名称空字符串 和 amq.direct
  • 扇形交换机(Fanout exchange) : 默认的预申明名称amq.fanout
  • 主题交换机(Topic exchange) : 默认的预申明名称amq.topic
  • 头部交换机(Headers exchange) : 默认的预申明名称amq.match,RabbitMQ使用amq.headers

交换机在声明的时候可以指定一些属性,重要的有:

  • 名称
  • 耐久性(在Broker重启后仍然存在)
  • 自动删除(交换机上的最后一个队列释放后,交换机会被删除)
  • 参数(Broker厂商特定的一些参数)

默认交换机

Broker上会存在一个默认交换机(无需使用者去声明),它的类型是Direct,并且没有名称(名称是空字符串)

直连交换机

exchange-direct.png

通过消息路由键(routing key)来向队列投递消息,工作原理:

  • 队列使用路由键绑定到交换机上
  • 当消息送达直连交换机时,根据队列的路由键和消息的路由键是否一致来路由消息.

扇形交换机

exchange-fanout.png

扇形交换机不使用路由键来路由消息,任何绑定到扇形交换机上的队列都会得到一份消息(拷贝).

主题交换机

主题交换机和直连交换机一样,依赖消息和队列的路由键来路由消息,不同的是,主题交换机在路由键匹配算法上灵活一些,支持通配符.

头部交换机

使用消息头中信息来决定消息路由.这样一来消息的路由就变成动态的了.

Queues

队列有以下相关属性:

  • 名称
  • 耐久性(在Broker重启后仍然存在)
  • 独占模式(只使用一个连接,并且随这个连接的关闭而删除)
  • 自动删除(在至少有一个消费者时,最后一个消费者取消订阅时队列自动被删除)
  • 参数(Broker厂商特定的一些参数)

在使用队列前必须先声明,可以重复声明,只有队列不存在时才会真正被创建.声明一个已经存在的队列但是属性却不一致就得到一个错误.

队列名称

  • 可以由应用程序指定,也可以由Broker自动生成(声明时,队列名称为空字符串),最大长度255字节,使用UTF-8编码.
  • 不能以amq.开头的,这是Broker内部使用的.

队列的耐久性

  • 具备耐久性的队列才会被持久化到磁盘上.
  • 队列的耐久性不会使队列中的消息获得持久化的能力,Broker重启后,只有具备持久化能力消息才会随之恢复.

Bindings

绑定是交换机将消息路由到队列的规则

扇形交换机是个例外

如果交换机无法将消息路由到任何队列,消息会被丢弃或者交还给publisher(取决于publisher给消息设置的属性值)

Consumers

只有花掉的钱才是你的钱,同样,消息只有被消费掉才有意义

应用程序有两种方法来消费消息:

  1. push模式(等Broker发过来)
  2. pull模式(自己去Broker上取)

push模式能够及时收到消息,但有可能会出现被强行喂饼的情况,因为Broker无法准确的知道应用程序的吞吐量如何.
pull模式会导致效率问题和延迟问题,pull频率太高会导致无用处的pull调用,频率低又不能及时拿到消息.

消费者可以用自己的consumer tag来取消订阅.

消息确认

消息确认有两种模式:

  • 自动确认:Broker将消息送达给应用程序后就认为可以确认了.
  • 显式确认:收到消息的应用程序需要明确回复一个ack.

消息预读取

用于设定消费者在下一次消息确认前可以拿到多少条消息(批量拿消息).

拒绝消息

应用程序在收到消息后,可以提出拒绝消息(可能叫退货更好理解),拒绝消息时可以告知Broker如何处理该消息:

  • 丢弃
  • 重新入队
  • 重新入队可能会导致再次收到该消息,从而进入一种无尽的循环.
  • 一次只能拒绝一条消息,这是AMPQ 0-9-1规范,但是,应用程序是可以一次接受多条消息的,这样一来就尴尬了.RabbitMQ为了处理这个问题,进行了协议扩展,称为Negative Acknowledgements

Message Attributes and Payload

消息也有相关的属性:

  • Content type: 类型
  • Content encoding:编码
  • Routing key:路由键
  • Delivery mode: 投递模式(是否持久化)
  • Message priority: 优先级
  • Message publishing timestamp: 发布时间戳
  • Expiration period: 过期时间
  • Publisher application id: 发布者的ID

有些属性可以被Broker识别并使用,但大多数都会传递给被消费者.

消息携带的数据称为Payload,一般来说这就是在应用直接传递的真实数据,因为AMQP保证Broker绝不会查看或者修改它.

Message Acknowledgements

使用哪种消息的确认模型需要看具体的需求,有时候自动确认就行了(收到即确认),有时候需要显式确认才行,典型的应用场景就是:消息的业务逻辑成功完成才算得上真正被消费了.

AMQP 0-9-1 Methods

略过

Connections

AMQP使用的是TCP长连接

Channels

应用程序在和Broker通讯时,不直接使用TCP连接,而是用Channel

Virtual Hosts

虚拟主机主要用于环境隔离,类似于namespace.

AMQP is Extensible

略过

AMQP 0-9-1 Clients Ecosystem

略过