基本架构

RabbitMQ整体上是一个生产者-消费者模型,主要负责接收、存储和转发消息。整体架构如下:

这里省略生产者、消费者等最基础的概念,主要介绍队列、交换器、路由键等。

队列

队列(Queue)是RabbitMQ的内部对象,用于存储消息。多个消费者可以订阅同一个队列,这时队列中的消息会被分摊(轮询)给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

交换器

生产者不是直接将消息发送到队列中,而是发送给交换器(Exchange),由交换器将消息路由到一个或者多个队列中。交换器主要有fanout、direct、topic、headers四种类型:

  • fanout:它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。
  • direct:它会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中。
  • topic:对direct类型的扩展,允许BindingKey和RoutingKey不严格的匹配它约定:
    • RoutingKey和BindingKey为一个点号.分隔的字符串,如com.rabbitmq.client
    • BindingKey中可以存在两种特殊字符串*#,用于做模糊匹配,其中*用于匹配一个单词,#用于匹配多规格单词(可以是零个)。
  • headers:headers类型的交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。在绑定队列和交换器时指定一组键值对,当发送消息到交换器时,RabbitMQ会获取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配队列和交换器绑定时指定的键值对,如果完全匹配则消息会路由到该队列,否则不会路由到该队列。这个类型基本不会使用。

路由键

生产者将消息发送给交换器的时候一般会指定一个RoutingKey,用来指定这个消息的路由规则,而这个RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。这里要注意BindingKey并不是所有情况下都生效,它依赖于交换器类型,比如fanout类型的交换器就会无视BindingKey,而是将信息路由到所有绑定到该交换器的队列中。

Connection与Channel

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

因为操作系统建立和销毁TCP连接是非常昂贵的开销,所以RabbitMQ采用TCP连接复用的方式,减少性能开销。

参考资料

  • RabbitMQ实战指南. 朱忠华