AMQP协议

一.引言

前期写了几篇Rabbit MQ的文章,对RabbitMQ的使用及SpringBoot框架下的客户端实现有了一定的了解。同时也对消息队列中间件的一些通用特性也得以切入,为了更加熟悉几种消息队列产品的底层网络实现,对AMQP这一协议及其模型的学习作以下记录,主要参照为AMQP的0-9-1版本。

二. AMQP是什么?

AMQP(高级队列消息协议)是一个网络协议,支持符合要求的客户端(application)和消息代理中间件(messaging middleware broker)之间进行通信。

消息代理:消息代理从发布者那里接收消息,并根据既定的路由规则,把接收到的消息发送给处理者,由于AMQP是个网络协议,所以这个过程中的发布者、消费者、消息代理可以存在于不同的设备上。

AMQP是一个可编程协议:从某种意义上说AMQP的实体和路由协议是由应用程序本身定义的,而不是由消息代理定义的。包括像声明队列和交换机,定义他们之间的绑定,订阅队列等等关于协议本身的操作。

三.AMQP模型介绍
  • 工作流程:发布者将消息发送给交换机,然后交换机将收到的消息根据路由规则分发给绑定的队列,最后AMQP代理会将消息投递给消费者,或者消费者按照需求自行获取。

    enter image description here

  • 一些特性:

    • 发布者发布消息时可以给消息指定各种消息属性,有些属性会被消息代理使用,然而其他的属性则是完全不透明的,它们只能被消费者使用
    • 网络是不可靠的,接收消息的应用也有可能在处理消息时失败。基于此原因,AMQP模块包含了一个消息确认的概念:消息代理将消息投递给消费者后,消费者会通知一下消息代理,这个可以是自动的也可以由处理消息的应用的开发者执行。当“消息确认”被启用时,消息代理不会将消息从队列中删除,直到收到消费者的确认回执。
    • 某些情况下,当一个消息无法被成功路由时,消息队列或许会被返回给发布者并丢弃。或者如果消息代理执行了延期操作,消息会被放入一个所谓的死信队列中。此时,消息发布者可以选择某些参数来处理这种特殊情况。
    • 队列、交换机、绑定统称为AMQP实体。

四. 交换机和交换机类型

a.交换机

  • 四种交换机类型:

    • 直连交换机 direct

    • 扇形交换机 fanout

    • 主题交换机 topic

    • 头交换机 header

  • 交换机的其他属性:

    • Name
    • Durability:消息代理重启后,交换机是否还存在
    • Auto-delete:与之绑定的消息队列都完成对此交换机的使用后,删除它
    • Arguments:依赖代理本身

b. 默认交换机

默认交换机是一个由消息代理预先声明好的没有名字(名字为空字符串)的直连交换机。用处:每个新建队列都会自动绑定到默认交换机上,绑定的路由键名称与队列名称相同。当声明了‘search-indexing-online’的队列,AMQP代理会自动将其绑定到默认交换机上。换句话说,默认交换机貌似能够直接将消息投递给队列,尽管技术上并没有作相关操作。

c 直连交换机 direct

直连交换机是根据携带的路由键将消息投递给对应队列的。直连交换机用来处理消息的单播路由。

  • 将一个队列绑定到一个交换机上,同时赋予该绑定一个路由键。
  • 当一个携带着路由键为R的消息被发送给直连交换机时,交换机会把它路由给绑定值同样为R的队列。

直连交换机经常用来循环分发任务给多个工作者。当这样做时,消息的负载均衡是发生在消费者之间,而不是队列之间。

enter image description here

d 扇形交换机 fanout

扇形交换机将消息路由给绑定到它身上的所有队列,而不理会绑定的路由键。如果有N个队列绑定到扇形交换机上,当有消息发送给此交换机上时,交换机会将消息的拷贝分别发送给这所有的N个队列。扇形交换机用来处理消息的广播路由。

应用案例:

  • 大规模用户在线程序可以用它来处理排行榜更新等全局事件
  • 体育新闻网站可以用它来近乎实时地将比分更新发布给移动客户端
  • 分发系统使用它来广播各种状态和配置更新
  • 在群聊消息时,它被用来分发消息给参与群聊的用户

enter image description here

e. 主题交换机

主题交换机通过对消息的路由键和队列到交换机的绑定模式之间的匹配,将消息路由给一个或多个队列。主题交换机通常用来实现各种分发/订阅模式的变种。主题交换机通常用来实现消息的多播路由。

当一个问题涉及到有针对性的选择需要接受消息的多消费者/多应用时,主题交换机都可以被列入考虑范围。使用案例:

  • 分发有关于特定地理位置的数据。如销售点
  • 多个工作者完成的后台任务,每个工作者负责处理某些特定的任务
  • 股票价格更新
  • 涉及到分类或者标签的新闻更新
  • 云端的不同服务的协调
  • 分布式架构给予软件系统的封装,其中每个构件者仅能处理一个特定的架构或系统

f. 头交换机

有时消息的路由涉及多个属性,此时使用消息头就比路由键更容易表达,头交换机就是为此而生。头交换机使用多个消息属性来代替路由键建立路由规则。通过消息头的值判断是否匹配路由规则。

我们可以将一个队列绑定到头交换机上,并给他们之间的绑定指定多个匹配的头。此时消息代理需要从应用开发者那里取到更多一段信息(x-match参数:any:任意匹配;all:全部匹配),换句话说它需要考虑某条消息是部分匹配上还是全部匹配上。

头交换机可以看作直连交换机的一种特殊形式,只不过不是使用路由键而是使用头属性。路由键必须为字符串,而头属性则没有这个限制。

五. 队列

存储着即将被应用消费掉的消息。队列跟交换机共享某些特殊属性,但是队列也有一些另外的属性

  • Name
  • Durable(消息代理重启后,队列依旧存在)
  • Exclusive:只被一个连接使用,而且当连接关闭后队列即被删除
  • Auto-delete: 当一个消费者退订后即被删除
  • Argument:一些消息代理用它来完成类似于TTL的某些额外功能。

队列在声明后才能使用。如果一个队列不存在,则会创建一个队列。如果声明的队列已经存在,并且属性完全相同,那么此次声明不会对原队列有任何影响,否则在属性不同的情况下会抛出403异常

a 队列名称

队列的名称可以由应用来取,也可以让消息代理生成一个,消息的长度最多255的utf-8字符串。

以‘amq.’开头的队列名称被预留做消息代理内部使用,自己声明时,会抛出403错误

b 队列持久化

持久化队列会被存储到磁盘上,当消息代理重启的时候,它依旧存在,反之被称作暂存队列。

被持久化的队列并不会使得路由到它的消息也具有持久性(尚未持久化)。只有持久化的消息才会被恢复。

c 绑定

Binding是交换机将消息路由给队列所遵循的规则。路由键/规则的意义在于从发送给交换机的众多消息中选择出某些消息,将其路由给指定队列。比如

  • 队列是纽约
  • 交换机是北京机场
  • 绑定就是北京机场到纽约的路线,路线可以是一条或多条。

拥有交换机这个中间层,很多由生产者直接路由到队列难以实现的路由方案能够得以实现,并且避免了应用开发者的许多重复劳动。

如果AMQP的消息无法路由到队列,消息就会被返回生产者或被销毁。这取决于发布者设置的消息属性。

六. 消费者

存在队列中的消息只有被消费,其价值才能够体现。消费的两种途径:

  • 将消息投递给应用,push API
  • 消费者根据需要主动获取消息,pull API

使用push API需要消费者指定它想要消费的消息,更像是应用订阅了一个队列。一个队列可以注册多个消费者,也可以注册一个独享的消费者。

每个消费者都有一个叫做消费者标签的标识符,可以用来退订消息,实际上是一个字符串。

七.消息

a 消息确认

  • 消费者处理消息时可能会失败或直接崩溃掉,那么AMQP代理什么时候删除消息才是正确的?AMQP规范给出了两种建议:

  • 自动确认模式:消费者代理将消息发送给消费者后立即删除

  • 显示确认模式:消费者发送一个确认回执后再删除消息。如果一个消费者在尚未发送回执的情况下挂掉了,那么AMQP代理会将消息重新投递给另一个消费者。如果当时没有可用的消费者,消息代理会死等下一个注册到此队列的消费者,然后尝试再次投递。

b. 拒绝消息

应用可以向消息代理表明,本条消息由于拒绝消息的原因处理失败了。当拒绝某条消息时,应用可以告诉消息代理如何处理这条消息-销毁或重新放回到队列中。当队列只有一个消费者时,请确认不要由于拒绝消息并且选择了重新放回到队列导致消息在同一个消费者身上无限循环的情况发生。

c 预取消息

在多个消费者消费同一个队列的案例中,明确指定在收到下一个确认回执前每个消费者可以预取多少条消息是非常有用的。

RabbitMQ只支持channel级别的预取。

d 消息属性和有效载荷

消息属性:

  • Content type(内容类型)
  • Content encoding(内容编码)
  • Routing key(路由键)
  • Delivery mode (persistent or not)
    投递模式(持久化 或 非持久化)
  • Message priority(消息优先权)
  • Message publishing timestamp(消息发布的时间戳)
  • Expiration period(消息有效期)
  • Publisher application id(发布应用的ID)

AMQP的消息除属性外,也含有一个有效载荷,被AMQP当作不透明的字符数组对待,它通常会使用类似JSON这种序列化格式的数据。

八. AMQP方法

  • 交换机操作方法

    • exchange.declare:客户端要求消息代理声明一个新的交换机,参数:交换机名称、类型、是否持久化等等。

    • exchange.declare-ok,返回通道号

    • exchange.delete

    • exchange.delete-ok

    以上的操作来自逻辑上的配对:exchange.declare 和 exchange.declare-ok,exchange.delete 和 exchange.delete-ok. 这些操作分为“请求 - requests”(由客户端发送)和“响应 - responses”(由代理发送,用来回应之前提到的“请求”操作)。

九. 网络连接

a 连接

AMQP的连接通常是长连接,使用TCP提供可靠投递的应用层协议,提供认证机制并且提供TLS(SSL)保护。当一个应用不再需要连接到AMQP代理的时候,需要优雅地关闭连接,而不是将TCP连接直接关闭。

有些应用程序需要与AMQP代理建立多个连接。,而同时使用多个TCP连接会消耗掉过多的资源并且使得防火墙配置变得困难。因此AMQP提供了通道来处理多连接,可以理解为TCP连接的多个轻量化连接。

一个特定通道的连接与其他通道是完全隔离的,因此每个AMQP方法都需要携带一个通道号,这样客户端就可以指定此方法是为那个通道准备的。

b 虚拟主机

为了在一个单独的代理上实现多个隔离的环境(用户、用户组、交换机、队列等)。AMQP提供了一个虚拟主机的概念。当连接建立时,AMQP客户端来指定使用哪个虚拟主机。

十. AMQP是可扩展的

AMQP 0-9-1 拥有多个扩展点:

  • 定制化交换机类型 可以让开发者们实现一些开箱即用的交换机类型尚未很好覆盖的路由方案。例如 geodata-based routing。
  • 交换机和队列的声明中可以包含一些消息代理能够用到的额外属性。例如RabbitMQ中的per-queue message TTL即是使用该方式实现。
  • 特定消息代理的协议扩展。例如RabbitMQ所实现的扩展。
  • 新的 AMQP 0-9-1 方法类可被引入。
  • 消息代理可以被其他的插件扩展,例如RabbitMQ的管理前端 和 已经被插件化的HTTP API。

因为AMQP协议的主要目标之一就是实现交互性,所以对于开发者来说,了解协议的操作方法而不是只停留在弄懂特定客户端的库就显得十分重要。这样使用不同类型的库与协议进行沟通时就会容易的多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值