RabbitMQ架构回顾

RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的。它的实现架构如下图所示:

各个组件介绍:
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列
Queue:消息的载体,每个消息都会被投到一个或多个队列
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来
Routing Key:路由关键字,exchange根据这个关键字进行消息投递
Producer:消息生产者,就是投递消息的程序
Consumer:消息消费者,就是接受消息的程序
Channel:消息通道,在客户端的每个连接里,可建立多个channel

AMQP协议介绍

目前Rabbitmq最新的版本默认支持的是AMQP 0-9-1,该协议总共包含了3部分:

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

AMQP生产者流转过程

接下来我们就来了解一些AMQP协议中生产者发送消息时所涉及到的相关命令,以及在发送数据的时候命令的传输的整体过程。
命令的传输流程(通过抓包工具进行抓取,选择虚拟机网卡)如下图所示:

  1. 当客户端与Broker建立连接的时候,客户端会向Broker发送一个Protocol Header 0-9-1的报文头,以此通知Broker本次交互才采用的是AMQP 0-9-1协议
  2. 紧接着Broker返回Connection.Start来建立连接,在连接的过程中涉及Connection.Start/.Start-OK、Connection.Tune/.Tune-OK、Connection.Open/.Open-OK这6个命令的交互;
  3. 连接建立以后需要创建通道,会使用到Channel.Open , Channel.Open-OK命令,在进行交换机声明的时候需要使用到Exchange.Declare以及Exchange.Declare-OK的命令。以此类推,在声明队列以及完成队列和交换机的绑定的时候都会使用到指定的命令来完成。
  4. 在进行消息发送的时候会使用到Basic.Publish命令完成,这个命令还包含了Conetent-Header和Content-Body。Content Header里面包含的是消息体的属性,Content-Body包含了消息体本身。
    由于我们本次演示的代码是spring boot和rabbitmq进行整合以后的代码,没有涉及到通道的关闭以及连接的释放,因此看不到关闭通道以及连接的相关命令传输过程。

AMQP消费者流转过程

接下来我们就来了解一些AMQP协议中消费消费时所涉及到的相关命令,以及在消费消息的时候命令的传输的整体过程。
命令的传输流程如下图所示:

我们发现消费者消费消息的时候,所涉及到的命令和生成者大部分都是相同的。在原有的基础之上,多个几
个命令:Basic.Qos/.Qos-OK以及Basic.Consume和Basic.Consume-OK。其中
Basic.Qos/.Qos-OK这两个命令主要用来确认消费者最大能保持的未确认的消息数时使用Basic.Consume和Basic.Consume-OK这两个命令主要用来进行消息消费确认。

AMQP命令概览

交换机的类型

fanout

扇型交换机(funout exchange)将消息路由给绑定到它身上的所有队列,而不理会绑定的路由键。如果 N个队列绑定到某个扇型交换机上,当有消息发送给此扇型交换机时,交换机会将消息的拷贝分别发送给这所有的 N 个队列。扇型用来交换机处理消息的广播路由(broadcast routing)。因为扇型交换机投递消息的拷贝到所有绑定到它的队列,所以他的应用案例都极其相似:

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

direct

直连型交换机(direct exchange)是根据消息携带的路由键(routing key)将消息投递给对应绑定键的队
列。直连交换机主要用来处理消息的单播路由(unicast routing)(尽管它也可以处理多播路由)。下边介绍它是如何工作的:

topic

前面提到的 direct 规则是严格意义上的匹配,换言之 Routing Key 必须与 Binding Key 相匹配的时候才将消息传送给 Queue.而Topic 的路由规则是一种模糊匹配,可以通过通配符满足一部分规则就可以传送。
它的约定是:
1)binding key 中可以存在两种特殊字符 * 与 # ,用于做模糊匹配,其中 * 用于匹配一个单词, # 用于匹配多个单词(可以是零个)
2)routing key 为一个句点号 “.” 分隔的字符串(我们将被句点号 “. ” 分隔开的每一段独立的字符串称为一个单词),如“topic.email”、“topic.sms”、
binding key 与 routing key 一样也是句点号 “.” 分隔的字符串。下面介绍它是如何工作的:

headers

headers 类型的 Exchange 不依赖于 routing key 与 binding key 的匹配规则来路由消息,而是根据发送的消息内容中的 headers 属性进行匹配。在绑定队列和交换机的时候指定一组键值对,当发生消息到交换机时,Rabbitmq会获取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配队列和交换机绑定时指定的键值对,如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers类型的交换机性能会很差,所以在生产环境中基本不会使用。下面介绍它是如何工作的:

“x-match”的匹配规则(就是上面介绍的all、any的规则)

小结:Rabbitmq中的这四种交换机,使用的较多的是direct。主要是基于两个原因:

  1. direct 交换机可以实现fanout的功能
  2. 性能排序:fanout > direct >> topic。