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
模型的图片
有三种参与者:
- 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,并且没有名称(名称是空字符串)
直连交换机
通过消息路由键(routing key)来向队列投递消息,工作原理:
- 队列使用路由键绑定到交换机上
- 当消息送达直连交换机时,根据队列的路由键和消息的路由键是否一致来路由消息.
扇形交换机
扇形交换机不使用路由键来路由消息,任何绑定到扇形交换机上的队列都会得到一份消息(拷贝).
主题交换机
主题交换机和直连交换机一样,依赖消息和队列的路由键来路由消息,不同的是,主题交换机在路由键匹配算法上灵活一些,支持通配符.
头部交换机
使用消息头中信息来决定消息路由.这样一来消息的路由就变成动态的了.
Queues
队列有以下相关属性:
- 名称
- 耐久性(在Broker重启后仍然存在)
- 独占模式(只使用一个连接,并且随这个连接的关闭而删除)
- 自动删除(在至少有一个消费者时,最后一个消费者取消订阅时队列自动被删除)
- 参数(Broker厂商特定的一些参数)
在使用队列前必须先声明,可以重复声明,只有队列不存在时才会真正被创建.声明一个已经存在的队列但是属性却不一致就得到一个错误.
队列名称
- 可以由应用程序指定,也可以由Broker自动生成(声明时,队列名称为空字符串),最大长度255字节,使用UTF-8编码.
- 不能以
amq.
开头的,这是Broker内部使用的.
队列的耐久性
- 具备耐久性的队列才会被持久化到磁盘上.
- 队列的耐久性不会使队列中的消息获得持久化的能力,Broker重启后,只有具备持久化能力消息才会随之恢复.
Bindings
绑定是交换机将消息路由到队列的规则
扇形交换机是个例外
如果交换机无法将消息路由到任何队列,消息会被丢弃或者交还给publisher(取决于publisher给消息设置的属性值)
Consumers
只有花掉的钱才是你的钱,同样,消息只有被消费掉才有意义
应用程序有两种方法来消费消息:
- push模式(等Broker发过来)
- 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
略过