RabbitMQ相关概念(三)

一、RabbitMQ的模型架构

在这里插入图片描述

Producer:生产者,就是投递消息的一方。
生产者创建消息,然后发布到RabbitMQ中。消息一般可以包含2个部分:消息体和标签(Label)。

Consumer:消费者,就是接收消息的一方。
消费者连接到RabbitMQ服务器,并订阅到队列上。当消费者消费一条消息时,只是消费消息的消息体(payload)。

Broker:消息中间件的服务节点。
一个RabbitMQ Broker可以简单地看作一个RabbitMQ服务节点,或者RabbitMQ服务实例。

Queue:队列,是RabbitMQ的内部对象,用于存储消息。
RabbitMQ中消息都只能存储在队列中,这一点和Kafka这种消息中间件相反。Kafka将消息存储在topic(主题)这个逻辑层面,而相对应的队列逻辑只是topic实际存储文件中的位移标识。RabbitMQ的生产者生产消息并最终投递到队列中,消费者可以从队列中获取消息并消费。
在这里插入图片描述

多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊(Round-Robin,即轮询)给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

RabbitMQ不支持队列层面的广播消费

Exchange:交换器,生产者将消息发送到Exchange,由交换器将消息路由到一个或者多个队列中。

RoutingKey:路由键。生产者将消息发给交换器的时候,一般会指定一个RoutingKey,用来指定这个消息的路由规则,而这个Routing Key需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。

在交换器类型和绑定键(BindingKey)固定的情况下,生产者可以在发送消息给交换器时,通过指定RoutingKey来决定消息流向哪里。

Binding:绑定。RabbitMQ中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键(BindingKey),这样RabbitMQ就知道如何正确地将消息路由到队列了。

生产者将消息发送给交换器时,需要一个RoutingKey,当BindingKey和RoutingKey相匹配时,消息会被路由到对应的队列中。

二、交换器类型

RabbitMQ常用的交换器类型有fanout、direct、topic、headers这四种。

fanout:它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。很像子网广播,每台子网内的主机都获得了一份复制的消息。

direct: 它会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中。
在这里插入图片描述
如果我们发送一条消息,并在发送消息的时候设置路由键为“warning”,则消息会路由到Queue1和Queue2;
如果在发送消息的时候设置路由键为“info”或者“debug”,消息只会路由到Queue2。

topic : 将消息路由到BindingKey和RoutingKey相匹配的队列中,但这里的匹配规则有些不同,它约定了一些规则:

  • RoutingKey为一个点号“.”分隔的字符串(被点号“.”分隔开的每一段独立的字符串称为一个单词),如“com.rabbitmq.client”、“java.util.concurrent”、“com.hidden.client”;
  • BindingKey和RoutingKey一样也是点号“.”分隔的字符串;
  • BindingKey中可以存在两种特殊字符串“*”和“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多规格单词(可以是零个)。
    -在这里插入图片描述

headers : headers类型的交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。在绑定队列和交换器时制定一组键值对,当发送消息到交换器时,RabbitMQ会获取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配队列和交换器绑定时指定的键值对,如果完全匹配则消息会路由到该队列,否则不会路由到该队列。

headers类型的交换器性能会很差,而且也不实用,基本上不会看到它的存在。

三、RabbitMQ运转流程

生产者发送消息的过程:

  1. 生产者连接到RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel)
  2. 生产者声明一个交换器,并设置相关属性,比如交换机类型、是否持久化等
  3. 生产者声明一个队列并设置相关属性,比如是否排他、是否持久化、是否自动删除等
  4. 生产者通过路由键将交换器和队列绑定起来
  5. 生产者发送消息至RabbitMQ Broker,其中包含路由键、交换器等信息
  6. 相应的交换器根据接收到的路由键查找相匹配的队列。
  7. 如果找到,则将从生产者发送过来的消息存入相应的队列中。
  8. 如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者
  9. 关闭信道。
  10. 关闭连接。

消费者接收消息的过程:

  1. 消费者连接到RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel)。
  2. 消费者向RabbitMQ Broker请求消费相应队列中的消息,可能会设置相应的回调函数,以及做一些准备工作。
  3. 等待RabbitMQ Broker回应并投递相应队列中的消息,消费者接收消息。
  4. 消费者确认(ack)接收到的消息。
  5. RabbitMQ从队列中删除相应已经被确认的消息。
  6. 关闭信道。
  7. 关闭连接。

Connection和Channel
在这里插入图片描述
生产者还是消费者,要和RabbitMQ Broker建立连接,这个连接就是一条TCP连接,也就是Connection。一旦TCP连接建立起来,客户端紧接着可以创建一个AMQP信道(Channel),每个信道都会被指派一个唯一的ID。信道是建立在Connection之上的虚拟连接,RabbitMQ处理的每条AMQP指令都是通过信道完成的。

完全可以直接使用Connection就能完成信道的工作,为什么还要引入信道呢?
RabbitMQ采用类似NIO(Non-blocking I/O)的做法,选择TCP连接复用,不仅可以减少性能开销,同时也便于管理。

四、AMQP协议介绍

RabbitMQ就是AMQP协议的Erlang的实现(当然RabbitMQ还支持STOMP 、MQTT等协议)。

AMQP协议本身包括三层:

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

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

AMQP生产者流转过程
在这里插入图片描述

AMQPP 消费者流转过程
在这里插入图片描述

NIO,也称非阻塞I/O,包含三大核心部分:Channel(信道)、Buffer(缓冲区)和Selector(选择器)。NIO基于Channel和Buffer进行操作,数据总是从信道读取数据到缓冲区中,或者从缓冲区写入到信道中。Selector用于监听多个信道的事件(比如连接打开,数据到达等)。因此,单线程可以监听多个数据的信道。NIO中有一个很有名的Reactor模式,有兴趣的读者可以深入研究。

STOMP,即Simple (or Streaming) Text Oriented Messaging Protocol,简单(流)文本面向消息协议,它提供了一个可互操作的连接格式,运行STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和平台上得到广泛的应用。

MQTT,即Message Queuing Telemetry Transport,消息队列遥测传输,是IBM开发的一个即时通信协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有物联网和外部连接起来,被用来当作传感器和制动器的通信协议。

猜你喜欢

转载自blog.csdn.net/Oooo_mumuxi/article/details/106223452