【RabbitMQ】RabbitMQ与AMQP协议简介(五)

一、AMQP与rabbitmq的关系

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

RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现。

二、AMQP messaging 中的基本概念

Connection
  • 对应底层一个AMQP-Client到RabbitMQ-Broker的一个TCP连接。
  • 这边要考虑两个端点问题,在TCP连接建立完成后,如下图所示,连接的目标Broker就已经确定是集群中的一台了,由于是长连接,除非断连重建,否则对端节点不可变。
  • 所以从这里可以看出RabbitMQ相比Pulsar、RocketMQ不一样的地方在于,其是一种服务端寻址模型,以Client的视角来看,想要连接任意Exchange、Queue,只要连上任意一台Broker就行。
Channel
  • 信道,可以理解为一种逻辑连接,体现了多路复用的设计思路。
  • 支持串行执行,包括收和发的指令,可以理解为一种半双工模式的“虚拟网络通道”。
  • 所有Exchange、Queue、Binding的操作都是在Channel之上进行的。
Vhost
  • 等价于一种租户隔离概念,不同Vhost下可以创建同名Exchange、Queue,这样可以进行业务隔离。
  • RabbitMQ的权限隔离和权限控制的机制是在Vhost级别的。
  • Rabbit官方原生的全局Policy控制在Vhost级别。
Exchange
  • 一个虚拟实体,声明不同消息的路由策略,自身不存储消息。
  • 一个路由器,基于消息头部的RoutingKey和Header将消息路由到符合条件的具体的Queue。
  • 支持单播和广播。
Queue
  • 消息存储实体,是消息底层存储的容器,类似Pulsar的Topic。
  • 单订阅模式,其下的Consumer分别消费到一部分消息。
  • 和存储关联,因此有容量上限、ttl等存储层的特性。
  • 支持多消费和独占消费,取决于你订阅时设置的参数。由于它是存储消息系统的消息,所以内部基于一个消费位点控制持久化消费进度,记录最后被消费并Ack的位置。
  • 面向Consumer。
Binding
  • 衔接Exchange和Queue的桥梁,本质是一个规则的声明。
  • 一个Exchange下可以有多个Binding。
  • 一个Queue也可以被多个Binding关联。
  • 一个Exchange到一个Queue也可以声明多个Binding。
Broker
  • 可以看做RabbitMQ的服务节点。一般请下一个Broker可以看做一个RabbitMQ服务器

三、AMQP协议本身包括三层:

  • Module Layer:位于协议的最高层,主要定义了一些供客户端调用的命令,客户端可以利用这些命令实现自己的业务逻辑。例如:客户端可以使用Queue.Declare命令声明一个队列或者使用Basic.Consum订阅消费一个队列中的消息。
  • Session Layer:位于中间层,主要负责将客户端的命令发送给服务器,再将服务器的应答返回给客户端,主要为客户端与服务器之间的通信提供可靠性同步机制和错误处理。
  • Transport Layer:位于最底层,主要传输二进制数据流,提供帧的处理、信道复用、错误检测和数据表示等。

AMQP说到底还是一个通信协议,通信协议都会涉及报文交互,从low-level层面举例来说,AMQP本身是应用层的协议,其填充于TCP协议层的数据部分,而从high-level层面来说,AMQP是通过协议命令交互的。AMQP协议可以看作是一系列结构化命令的集合,这里的命令代表一种操作,类似于Http中的方法(GET、POST、PUT、DELETE等)

AMQP生产者流转过程

当客户端与Broker(RabbitMQ服务器)建立连接的时候,会调用factory.newConnection方法,这个方法会进一步封装成Protocol Header的报文头发送给Broker,以此来通知Broker本次交互采用的是AMQP协议,紧接着Broker返回Connection.Start来建立连接,在连接的过程中涉及Connection.Start/.Start-OK、Connection.Tune/.Tune-OK、Connection.Open/.Open-ok这6个命令的交互。

  当客户端调用connection.createChannel方法准备开启信道的时候,其包装Channel.Open命令发送给Broker,等待Channel.Open-Ok命令。

  当客户端发送消息的时候,需要调用channel.basicPublish方法,对应的AMQP命令为Basic.Publish,注意这个命令和前面涉及的命令略有不同,这个命令还包括了Content Header和Content Body。Content Header里面包含的是消息体的属性,例如:投递模式、优先级等,而Content Body包含消息体的本身。

  当客户端发送完消息需要关闭资源时,涉及Channel.Close/.Close-Ok与Connection.Close/.Close-Ok的命令交互。详细的流转过程如下图

AMQP消费者流转过程

消费者客户端同样需要与Broker建立连接,与生产者客户端一样,协议交互同样涉及Connection.Start/.Start-Ok、Connection.Tune/.Tune-Ok和Connection.Open/.Open-Ok等。

  紧接着就是在Connection之上建立channel,和之前的生产者一样协议涉及Channel.Open/Open-Ok。

  如果在消费之前调用了Channel.basicQos(int prefetchCount)的方法来设置消费者客户端最大能“保持”的未确认的消息数(即预取个数),那么协议流转就会涉及Basix.Qos/.Qos-Ok这两个AMQP命令。

  在真正的消费之前,消费者客户端需要向Broker发送Basic.Consume命令(即调用channel.basicConsume方法)将Channel设置为接收模式,之后Broker回执Basic.Consume-Ok以告诉消费者客户端准备好消费消息。紧接着Broker向消费者客户端推送消息(Push),即Basic.Deliver命令,有意思的是这个和Basic.Publish命令一样会携带Content Header 和Content Body。

  消费者接收到消息并正确消费后,向Broker发送确认,即Basic.Ack命令。

  在消费者停止消费的时候,主动关闭连接,这点和生产者是一样的,涉及到Channel.Close/Channel-Ok和Connection.Close/.Close-Ok。

参考:

https://www.cnblogs.com/Joe-Go/p/10858647.html

https://www.cnblogs.com/wutianqi/p/10043011.html

posted @ 2022-01-22 00:00  二月无雨  阅读(350)  评论(0编辑  收藏  举报