RabbitMQ——消息服务概述、RabbitMQ的概述

目录


一、消息服务概述

  1. 大多应用中,可通过消息服务中间件来提升系统异步通信、扩展解耦能力。

  2. 消息服务中两个重要概念:
    消息代理(message broker)目的地(destination)
    当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。

  3. 消息队列主要有两种形式的目的地
    队列(queue)点对点消息通信(point-to-point)
    主题(topic)发布(publish)/订阅(subscribe)消息通信

  4. 点对点式:
    – 消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容,消息读取后被移出队列
    – 消息只有唯一的发送者和接受者,但并不是说只能有一个接收者

  5. 发布订阅式:
    – 发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个主题,那么就会在消息到达时同时收到消息

  6. JMS(Java Message Service)JAVA消息服务:
    – 基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现

  7. AMQP(Advanced Message Queuing Protocol)
    – 高级消息队列协议,也是一个消息代理的规范,兼容JMS
    RabbitMQ是AMQP的实现

在这里插入图片描述

  1. Spring支持
    – spring-jms提供了对JMS的支持
    – spring-rabbit提供了对AMQP的支持
    – 需要ConnectionFactory的实现来连接消息代理
    – 提供JmsTemplate、RabbitTemplate来发送消息
    @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息代理发布的消息
    @EnableJms@EnableRabbit开启支持

  2. Spring Boot自动配置
    – JmsAutoConfiguration
    RabbitAutoConfiguration

二、解决问题

跳转到目录

1、异步处理

场景说明:用户注册后,需要发注册邮件和注册短信,传统的做法有两种:a)串行的方式;b)并行的方式

串行方式:将注册信息写入数据库后,发送注册邮件,再发送注册短信,以上三个任务全部完成后才返回给客户端。 这有一个问题是:邮件,短信并不是必须的,它只是一个通知,而这种做法让客户端等待没有必要等待的东西。
在这里插入图片描述
并行方式:将注册信息写入数据库后,发送邮件的同时,发送短信,以上三个任务完成后,返回给客户端,并行的方式能提高处理的时间。
在这里插入图片描述
假设三个业务节点分别使用50ms,串行方式使用时间150ms,并行使用时间100ms。虽然并性已经提高的处理时间,但是,前面说过,邮件和短信对我正常的使用网站没有任何影响,客户端没有必要等着其发送完成才显示注册成功,应该是写入数据库后就返回。

消息队列:引入消息队列后,把发送邮件,短信不是必须的业务逻辑异步处理:
在这里插入图片描述
由此可以看出,引入消息队列后,用户的响应时间就等于写入数据库的时间+写入消息队列的时间(可以忽略不计),引入消息队列后处理后,响应时间是串行的3倍,是并行的2倍。

2、应用解耦

场景:双11是购物狂节,用户下单后,订单系统需要通知库存系统,传统的做法就是订单系统调用库存系统的接口。
在这里插入图片描述
这种做法有一个缺点:

  • 当库存系统出现故障时,订单就会失败。
  • 订单系统和库存系统高耦合。

引入消息队列:
在这里插入图片描述

  • 订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。

  • 库存系统:订阅下单的消息,获取下单消息,进行库操作。就算库存系统出现故障,消息队列也能保证消息的可靠投递,不会导致消息丢失。

3、流量削锋

流量削峰一般在秒杀活动中应用广泛。

场景:秒杀活动,一般会因为流量过大,导致应用挂掉,为了解决这个问题,一般在应用前端加入消息队列。

作用:

  • 可以控制活动人数,超过此一定阀值的订单直接丢弃
  • 可以缓解短时间的高流量压垮应用(应用程序按自己的最大处理能力获取订单)
    在这里插入图片描述
    用户的请求,服务器收到之后,首先写入消息队列,加入消息队列长度超过最大值,则直接抛弃用户请求或跳转到错误页面。秒杀业务根据消息队列中的请求信息,再做后续处理。

三、RabbitMQ概述

跳转到目录
MQ 全称为 Message Queue,是一种分布式应用程序的的通信方法,是``消费者-生产者模型的典型的代表,producer 往消息队列中不断写入消息,而另一端 consumer 则可以读取或者订阅队列中的消息,这点可以与数据结构中队列的作用相类似,具有 FIFO 的特点。

RabbitMQ 是 MQ 产品的典型实现,是基于 AMQP 协议可复用的企业消息系统。业务上,可以实现服务提供者和消费者之间的数据解耦,提供高可用性的消息传输机制,在实际生产中应用相当广泛。

1、消息队列

首先来一张消息队列的经典图,可以划分为三个角色: Producer, Queue, Consumer
在这里插入图片描述

  • Queue:为承载消息的容器,为什么是队列而不是栈呢?主要是因为绝大部分的场景,我们都是希望消息是先进先出,有顺序的
  • Producer:生产者,就是产生消息,并不断往队列塞的角色
  • Consumer:消费者,也就是不断从队列中获取消息的角色

2、理解消息队列

其实在生活中,这种模型用得非常多,就比如我们都会接触的网购快递,可以说是一个典型的消息队列的 例子了:

商家不断的把商品扔给快递公司(注意不是直接将商品给买家),而快递公司则将商品根据地质分发对应的买家

对上面这个过程进行拆解,可以映射扮演的角色

  • 商品:Message,传递的消息,由商家投递给快递公司时,需要进行打包(一般Producer生产消息也会将实体数据进行封装)
  • 商家:Produer 生产者
  • 快递公司: Queue,消息的载体
  • 买家:Consumer 消费者

那么快递公司时怎么知道要把商品给对应的买家呢?根据包裹上的地址+电话

  • 同样消息队列也需要一个映射规则,实现Message和Consumer之间的路由

3、RabbitMQ的基本概念

在这里插入图片描述

核心概念:
  • Message:消息,包含消息头(即附属的配置信息)和消息体(即消息的实体内容)消息,消息体是不透明的,消息体是由一些可选属性组成的,包括路由键(routing-key)、优先级(priority)、持久性存储(delivery-mode)等。

    • Exchange(交换机)就是通过路由键来将消息路由到哪个消息队列中;
  • Publisher:消息生产者,向交换机发布消息的客户端程序,我们可以简单理解为就是一个 Java 程序。

  • Exchange:交换机,用来接收生产者发送的消息并将这些消息路由给服务器中的消息队列

    常见的三种交换器类型:
    direct:发布与订阅,完全匹配 。我们可以简单理解为一对一的关系,一个交换器将消息发送给一个队列,是完全匹配的
    fanout:广播,所有订阅该广播的队列都可以收到该消息。广播式交换器,不管消息的 ROUTING_KEY 设置为什么,Exchange 都会将消息转发给所有绑定的 Queue
    topic:主题,规则匹配 。

  • Queue:消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。

  • Binding:绑定,用于给 Exchange(交换机) 和 Queue(消息队列) 建立关系,把 exchange 和 queue 按照路由规则绑定起来, 可以是多对多的关系。

  • Connection:网络连接

  • Channel:信道,MQ(消息队列)与外部打交道都是通过Channel来的,发布消息、订阅队列还是接收消息,这些动作都是通过Channel完成;简单来说就是消息通过Channel塞进队列或者流出队列。在客户端的每个连接里,可建立多个channel。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。

  • Consumer:消费者,从消息队列中获取消息的客户端应用程序。

  • Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是/一个 broker 里可以有多个 vhost,用作不同用户的权限分离。

  • Broker:消息队列服务器实体,它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输。可以理解为在 Linux 上创建的虚拟机实体。

4、通信过程

  1. 生产者(Publisher)生产消息, 消息通过Channel(信道)发送给Broker(服务器主体), Broker再分配给一个Exchange(交换机)
  2. Exchange收到消息后, 通过消息中的ROUTEKEY(路由键), 将消息转发给匹配的Queue(消息队列)
  3. Queue收到消息后, 将消息通过Channel发送给消费者(Consumer)
  4. Consumer收到消息后, 发送ACK(确认标志)给消息队列确认收到消息
  5. Queue收到ACK, 删除该消息队列中缓存的此条消息.

四、RabbitMQ运行机制

跳转到目录
AMQP 中的消息路由

  • AMQP 中消息的路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 ExchangeBinding 的角色。生产者把消息发布到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列。
    在这里插入图片描述
Exchange类型

Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:directfanouttopicheaders 。headers 匹配 AMQP 消息的 header 而不是路由键, headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型:

在这里插入图片描述
消息中的路由键(routing key)如果和 Binding 中的binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发 routing key 标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard”等等。它是完全匹配、单播的模式。

在这里插入图片描述
每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout 类型转发消息是最快的。

在这里插入图片描述
topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配一个单词。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章