在最初状态下,生产者发送消息的时候

(1) 生产者连接到RabbitMQ Broker , 建立一个连接( Connection) ,开启一个信道(Channel)

(2) 生产者声明一个交换器,并设置相关属性,比如交换机类型、是否持久化等

(3) 生产者声明一个队列井设置相关属性,比如是否排他、是否持久化、是否自动删除等

( 4 ) 生产者通过路由键将交换器和队列绑定起来

( 5 ) 生产者发送消息至RabbitMQ Broker,其中包含路由键、交换器等信息

(6) 相应的交换器根据接收到的路由键查找相匹配的队列。

( 7 ) 如果找到,则将从生产者发送过来的消息存入相应的队列中。

(8) 如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者

(9) 关闭信道。

(1 0) 关闭连接。

消费者接收消息的过程:

(1)消费者连接到RabbitMQ Broker ,建立一个连接(Connection ) ,开启一个信道(Channel) 。

(2) 消费者向RabbitMQ Broker 请求消费相应队列中的消息,可能会设置相应的回调函数,

以及做一些准备工作

(3)等待RabbitMQ Broker 回应并投递相应队列中的消息, 消费者接收消息。

(4) 消费者确认( ack) 接收到的消息。

( 5) RabbitMQ 从队列中删除相应己经被确认的消息。

( 6) 关闭信道。

( 7) 关闭连接。

如图2-9 所示,我们又引入了两个新的概念: Connection 和Channel 。我们知道无论是生产

者还是消费者,都需要和RabbitMQ Broker 建立连接,这个连接就是一条TCP 连接,也就是

Connection 。一旦TCP 连接建立起来,客户端紧接着可以创建一个AMQP 信道(Channel) ,每

个信道都会被指派一个唯一的D 。信道是建立在Connection 之上的虚拟连接, RabbitMQ 处理

的每条AMQP 指令都是通过信道完成的。

RabbitMQ 运转流程_RabbitMQ

 

我们完全可以直接使用Connection 就能完成信道的工作,为什么还要引入信道呢?试想这

样一个场景, 一个应用程序中有很多个线程需要从RabbitMQ 中消费消息,或者生产消息,那

么必然需要建立很多个Connection ,也就是许多个TCP 连接。然而对于操作系统而言,建立和

销毁TCP 连接是非常昂贵的开销,如果遇到使用高峰,性能瓶颈也随之显现。RabbitMQ 采用

类似NIO' (Non-blocking 1/0) 的做法,选择TCP 连接复用,不仅可以减少性能开销,同时也

便于管理。

NIO' ,也称非阻塞UO , 包含三大核心部分Channel (信道)、Buffer (缓冲区)和Selector (选择器). NIO 基于Channel 和

Buffer 进行操作,数据总是从信道读取数据到缓冲区中,或者从缓冲区写入到信道中。Selector 用于监听多个信道的事件(比

如连接打开,数据到达等)。因此,单线程可以监听多个数据的信道。NIO 中有一个很有名的Reactor 模式,有兴趣的读者可以

深入研究。

每个线程把持一个信道,所以信道复用了Connection 的TCP 连接。同时RabbitMQ 可以确

保每个线程的私密性,就像拥有独立的连接一样。当每个信道的流量不是很大时,复用单一的

Connection 可以在产生性能瓶颈的情况下有效地节省TCP 连接资源。但是当信道本身的流量很

大时,这时候多个信道复用一个Connection 就会产生性能瓶颈,进而使整体的流量被限制了。

此时就需要开辟多个Connection ,将这些信道均摊到这些Connection 中, 至于这些相关的调优

策略需要根据业务自身的实际情况进行调节.

信道在AMQP 中是一个很重要的概念,大多数操作都是在信道这个层面展开的。在代码清单

1-1 中也可以看出一些端倪,比如chan ne l . exchangeDeclare 、channel . queueDeclare 、

channel . basicPublish 和channel . basicConsume 等方法。RabbitMQ 相关的API 与AMQP

紧密相连,比如channel.basicPublish 对应AMQP 的Basic.Publish 命令.