整理RabbitMQ介绍
RabbitMQ介绍
使用Erlang语言实现的消息中间件,用于在分布式系统中存储转发消息。
RabbitMQ模型
RabbitMQ 整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。可以把消息传递的过程想象成:当你将一个包裹送到邮局,邮局会暂存并最终将邮件通过邮递员送到收件人的手上,RabbitMQ就好比由邮局、邮箱和邮递员组成的一个系统。从计算机术语层面来说,RabbitMQ 模型更像是一种交换机模型。
生产者与消费者
生产者 Producer
生产消息的一方
消费者 Consumer
使用消息的一方
交换机
交换机 Exchange
交换机接收生产者发送的消息并将这些消息路由到队列中。
在RabbitMQ中,消息并不是直接被投递到消息队列中的,中间还必须经过交换机这一层,交换机会把我们的消息分配到对应的消息队列中。
交换机有四种类型,不同类型对应不同的路由策略。
direct、fanout、topic、headers
路由键、绑定键
生产者发消息给交换机的时候,一般会指定一个路由键 RoutingKey,用来指定这个消息的路由规则,而这个RoutingKey需要与交换机类型和绑定键 BindingKey联合使用才能最终生效。
RabbitMQ中通过 绑定 Binding 将交换机和消息队列关联起来,在绑定的时候一般会指定一个绑定键,这样RabbitMQ就知道如何正确将消息路由到队列了。如下图:
一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。Exchange 和 Queue 的绑定可以是多对多的关系。
生产者将消息发送给交换器时,需要一个RoutingKey,当 BindingKey 和 RoutingKey 相匹配时,消息会被路由到对应的队列中。在绑定多个队列到同一个交换器的时候,这些绑定允许使用相同的 BindingKey。BindingKey 并不是在所有的情况下都生效,它依赖于交换器类型,比如fanout类型的交换器就会无视,而是将消息路由到所有绑定到该交换器的队列中。
消息队列
消息队列Queue 用来保存消息,直到消息发送给消费者。
消息队列是消息的容器,一个消息可投入一个或多个队列中。
RabbitMQ中,消息只能存储在队列中,这一点和Kafka相反。Kafka将消息存储在 topic(主题) 这个逻辑层面,而相对应的队列逻辑只是topic实际存储文件中的位移标识。
多个消费者可以订阅一个队列,队列中的消息会被轮询分配(Round-Robin)给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理,这样可以避免消息被重复消费。
RabbitMQ不支持队列层面的广播消费。
Broker服务节点
一个RabbitMQ Broker可以简单地看作一个 RabbitMQ 服务节点,或者RabbitMQ服务实例。大多数情况下也可以将一个RabbitMQ Broker看作一台 RabbitMQ 服务器。
下图展示了生产者将消息存入 RabbitMQ Broker,以及消费者从Broker中消费数据的整个流程。
交换机类型
direct
不指定交换机类型时,默认位direct。
路由规则:把消息路由到那些 Bindingkey 与 RoutingKey 完全匹配的 Queue中。如下图:
如果发送消息的时候设置路由键为“warning”,那么消息会路由到 Queue1 和 Queue2。
如果发送消息的时候设置路由键为"Info”或者"debug”,消息只会路由到Queue2。
如果以其他的路由键发送消息,则消息不会路由到这两个队列中。
direct 类型常用在处理有优先级的任务,根据任务的优先级把消息发送到对应的队列,这样可以指派更多的资源去处理高优先级的队列。
fanout
路由规则:
把所有发送到该 Exchange 的消息路由到所有与它绑定的 Queue 中,不需要做任何判断操作,所以 fanout 类型是所有的交换机类型中速度最快的。fanout 类型常用来广播消息。
topic
前面讲到direct类型的交换机路由规则是完全匹配路由键和绑定键的,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的交换机在匹配规则上进行了扩展,它约定:
- RoutingKey 为一个点号“ . ”分隔的字符串(被点号“ . ”分隔开的每一段独立的字符串称为一个单词),如 “com.rabbitmq.client”、“java.util.concurrent”、“com.hidden.client”;
- BindingKey 和 RoutingKey 一样也是点号“ . ”分隔的字符串;
- BindingKey 中可以存在两种特殊字符串“”和“#”,用于做模糊匹配,其中“”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
以上图为例:
- 路由键为 “com.rabbitmq.client” 的消息会同时路由到 Queuel 和 Queue2;
- 路由键为 “com.hidden.client” 的消息只会路由到 Queue2 中;
- 路由键为 “com.hidden.demo” 的消息只会路由到 Queue2 中;
- 路由键为 “java.rabbitmq.demo” 的消息只会路由到Queuel中;
- 路由键为 “java.util.concurrent” 的消息将会被丢弃或者返回给生产者(需要设置 mandatory 参数),因为它没有匹配任何路由键。
headers(不推荐使用)
headers 类型的交换机不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的 headers 属性进行匹配。
在绑定队列和交换机时制定一组键值对,当发送消息到交换机时,RabbitMQ会获取到该消息的 headers(也是一个键值对的形式)对比其中的键值对是否完全匹配队列和交换机绑定时指定的键值对,如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers 类型的交换机性能会很差,而且也不实用,基本上不会看到它的存在。
死信队列
顾名思义,就是消息队列中的消息因为某些原因导致无法被消费,这样的消息没有后续的处理,为了处理这些死信消息,就有了死信队列。
应用场景:为了保证消息数据不丢失,当消息发生异常时,将消息放入死信队列中。比如订单系统,当订单在支付页面指定时间内没有付款,订单过期,但为了保证订单信息不丢失,放入死信队列中。
死信的来源
消息TTL过期
TTL是Time To Live的缩写,也就是消息的生存时间
队列达到最大长度
队列满了,无法放入消息到MQ中
消息被拒绝
(basic.reject 或 basic.nack) 并且 requeue=false
七种队列模式
简单模式
一个生产者对应一个消费者,RabbitMQ相当于一个消息代理,负责将A的消息转发给B
应用场景:将发送的电子邮件放到消息队列,然后邮件服务在队列中获取邮件并发送给收件人
工作队列模式
在多个消费者之间分配任务(竞争的消费者模式),一个生产者对应多个消费者,一般适用于执行资源密集型任务,单个消费者处理不过来,需要多个消费者进行处理
应用场景:一个订单的处理需要10s,有多个订单可以同时放到消息队列,然后让多个消费者同时处理,这样就是并行了,而不是单个消费者的串行情况
发布订阅模式
一次向许多消费者发送消息,一个生产者发送的消息会被多个消费者获取,也就是将消息将广播到所有的消费者中。
应用场景:更新商品库存后需要通知多个缓存和多个数据库,这里的结构应该是:
一个fanout类型交换机扇出两个个消息队列,分别为缓存消息队列、数据库消息队列
一个缓存消息队列对应着多个缓存消费者
一个数据库消息队列对应着多个数据库消费者
路由模式
有选择地(Routing key)接收消息,发送消息到交换机并且要指定路由key ,消费者将队列绑定到交换机时需要指定路由key,仅消费指定路由key的消息
应用场景:如在商品库存中增加了1台iphone12,iphone12促销活动消费者指定routing key为iphone12,只有此促销活动会接收到消息,其它促销活动不关心也不会消费此routing key的消息
主题模式
根据主题(Topics)来接收消息,将路由key和某模式进行匹配,此时队列需要绑定在一个模式上,“#” 匹配一个词或多个词,“*“ 只匹配一个词。
应用场景:同上,iphone促销活动可以接收主题为iphone的消息,如iphone12、iphone13等
RPC远程调用
如果我们需要在远程计算机上运行功能并等待结果就可以使用RPC,具体流程可以看图。
应用场景:需要等待接口返回数据,如订单支付
发布者确认
与发布者进行可靠的发布确认,发布者确认是RabbitMQ扩展,可以实现可靠的发布。在通道上启用发布者确认后,RabbitMQ将异步确认发送者发布的消息,这意味着它们已在服务器端处理
应用场景:对于消息可靠性要求较高,比如钱包扣款。
你应当热爱自由!
作者:Leejk,转载请注明原文链接:https://www.cnblogs.com/leejk/p/15103829.html