RabbitMQ是什么?

RabbitMQ是一个由erlang语言开发的消息队列中间件。消息队列是一种应用程序对应用程序的通信方法。使用消息队列,程序之间不必通过互相调用通信,而是利用消息中间件来进行数据的传递。目前比较流行的消息队列中间件还有ActiveMQ、RocketMQ和Kafka。

为什么要使用RabbitMQ?

消息队列凭借其独到的特性,在不同的场景可以展现不同的作用 。今天就来说一说其最主要的使用场景:解耦、异步、削峰。

1、解耦

为什么用rabbitMQ不用redis_为什么用rabbitMQ不用redis


现有订单、日志、库存服务,其中日志服务和库存服务都需要调用订单服务,如果订单服务出现故障或者其供其他服务调用的接口出现故障,那么依赖它的服务都会无法正常工作;如果后续增加其它服务如支付服务等,新增服务也需要调用订单服务,订单服务需要为每个新增的服务增加调用的接口,耦合性比较严重。这种情况下,引入消息队列的优势就体现出来了,如下:

为什么用rabbitMQ不用redis_键值对_02


用户下单之后,订单服务完成自身服务的工作,将消息写入消息队列之中,其余服务只需要订阅消息队列即可,不与订单服务打交道,降低了服务之间的耦合性。

2、异步

为什么用rabbitMQ不用redis_键值对_03


假设,现有如下业务。系统B和系统C需要系统A先一步完成,然后系统B和C才执行,如上图所示,这是一种同步执行的方式,比较耗时。我们对其进行优化,引入消息队列,如下:

为什么用rabbitMQ不用redis_消息队列_04


系统A完成其业务之后,将信息写入消息队列,系统B和C订阅消息,以异步方式执行,较少了系统的执行时间。

3、削峰

削峰常见于各种秒杀、促销等系统中,由于瞬间请求量很大,数据库无法正常工作,所以需要借助消息队列,将请求先存入消息队列。然后根据数据库的处理能力,慢慢从消息队列中拉取消息,处理并存储到数据库。

RabbitMQ相关概念

大致了解了消息队列的常见使用情况之后,我们来看一下消息队列之一RabbitMQ的一些基础概念。

1、生产者和消费者

生产者(Producer):生产者,就是向MQ投递消息的一方。

消费者(Consumer):消费者,就是接收消息的一方。

2、队列

队列(Queue):队列是RabbitMQ内部的对象,用于存储消息。消费者就是从队列中取出消息。多个消费者可以订阅同一个队列,这时队列中的消息会被分摊给所有的消费者,而并非每个消费者都收到所有消息。

3、交换机、路由、绑定

RabbitMQ中,生产者永远不会将任何消息直接发送到队列,甚至它不知道消息是否会被传递到队列,而将消息投递到交换机(Exchange)上,再由交换机将消息路由到一个个的队列中,如果没有匹配的路由,消息将被丢弃(默认)。

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

绑定(Binding): RabbitMQ 中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键 (BindingKey),当 BindingKey 与 RoutingKey 相匹配的时候,消息就可以被正确地路由到对应的队列中,但是 BindingKey 是依赖于交换机类型的,不同的交换机类型对于 BindingKey 有不同的处理。

详细的路由、绑定规则会在下面介绍交换机类型时一起介绍。

4、交换机类型

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

fanout(扇出):fanout类型的交换机会将消息发送到所有与之绑定的队列上面,而忽略生产者指定的RoutingKey。

为什么用rabbitMQ不用redis_键值对_05


交换机 X 会将消息发送到每个与之绑定的队列上。direct(路由):direct类型的交换机会将消息路由到 BindingKey 与消息的 RoutingKey 完全匹配的队列上。

为什么用rabbitMQ不用redis_消息队列_06


如上图,当消息的 RoutingKey 是error 时,消息会被发送到名为amqp.gen-Spb…的队列;当消息的 RoutingKey 是 info 、error 或者 warning 时,消息会被发送到名为amqp.gen-Agl…的队列。

注意:这里当消息的 RoutingKey 是error 时,消息会被同时发送到 amqp.gen-Spb…和 amqp.gen-Agl… 队列。

topic(主题):前面谈到的 direct 类型的交换器路由规则是完全匹配 BindingKey 和 RoutingKey,但是这种严格的匹配方式在很多情况下不能满足实际业务的需求。 topic 类型的交换机在其基础上引入了通配符,进行了扩展。匹配规则如下:

1、RoutingKey 和 BindingKey 都是一个以小数点"."分隔的字符串。如,com.fcml.test

2、“*” 通配符表示匹配任意一个单词;“#” 通配符表示匹配 任意零个或多个单词。

为什么用rabbitMQ不用redis_为什么用rabbitMQ不用redis_07


如上图,RoutingKey 由三个单词通过.连接而成并且第二个单词是orange 时,消息会被发送到Q1队列;RoutingKey 由三个单词通过.连接而成并且第三个单词是rabbit 时,消息会被发送到Q1队列;RoutingKey 只要由 lazy.开头,消息就会转发到Q2队列。

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


初学RabbitMQ,笔记难免出错,希望大家多提意见和建议。