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 指令都是通过信道完成的。

7

我们完全可以直接使用 Connection 就能完成信道的工作,为什么还要引入信道呢?
试想这样一个场景,一个应用程序中有很多个线程需要从 RabbitMQ 中消费消息,或者生产消息,
那么必然需要建立很多个 Connection,也就是许多个 TCP 连接。然而对于操作系统而言,建立和销毁 TCP 连接是非常昂贵的开销,
如果遇到使用高峰,性能瓶颈也随之显现。RabbitMQ 采用类型 NIO(Non-blocking I/O)的做法,
选择 TCP 连接复用,不仅可以减少性能开销,同时也便于管理。

每个线程把持一个信道,所以信道复用了 Connection 的 TCP 连接。
同时 RabbitMQ 可以确保每个线程的私密性,就像拥有独立的连接一样。
当每个信道的流量不是很大时,复用单一的 Connection 可以在产生性能瓶颈的情况下有效地节省 TCP 连接资源。
但是当信道本身的流量很大时,这时候多个信道复用一个 Connection 就会产生性能瓶颈,进而使整体的流量被限制了。
此时就需要开辟多个 Connection,将这些信道均摊到这些 Connection 中。

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