一.MQ简介
什么是MQ
MQ本质是队列,FIFO先入先出,队列中存放的内容是message(消息),还是一种跨进程的通信机制,用于上下游传递消息。在互联网架构中是常见的上下游“逻辑解耦+物理解耦”的消息通信服务。
主要用来实现流量削峰,应用解耦,异步处理等系统优化方案
为什么使用MQ
- 流量削峰:
例如:处理订单系统中能最大处理1万次订单,但在高峰期处理2万次订单处理不过来,只能限制1万次订单后的订单不能下单。那么有消息队列做缓冲就很好的解决这个问题,将这1秒内的订单分一段时间处理,意思没能处理的放在队列中等待直到处理完,这样比不能下单体验感好。 - 应用解耦:
在电商系统中有订单系统,库存系统,物流系统,支付系统,如果耦合调用它们任何一个子系统出故障下单会造成异常,这时使用消息队列后,用几分钟解决完故障后,继续处理订单,客户感受不到系统的故障,提升系统的可用性。 - 异步处理:
有些服务间是异步的
例如:A调用B,B花很长时间处理完,A不知道B什么时候处理完
以前方式解决:A过一段时间去调用B的API查询,或A提供一个callback api,B执行完调用API通知A服务。
使用消息总线后:A调用完B后,只需监听B处理完的消息,B处理完会发一条消息给MQ,MQ将此消息转发给A服务。
AMQP和JMS
MQ是消息通信的模型,并发具体实现。现在实现MQ的有两种主流方式:AMQP、JMS。
两者间的区别和联系:
JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式
JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。
JMS规定了两种消息模型;而AMQP的消息模型更加丰富
常见MQ产品
- ActiveMQ:基于JMS
- RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好
- RocketMQ:基于JMS,阿里巴巴产品,目前交由Apache基金会
- Kafka:分布式消息系统,高吞吐量
二.RabbitMQ(消息队列)
选用RabbitMQ
在消息队列产品的选择上,我选用了RabbitMQ。估计有很多同学质疑,为什么不选择Kafka呢?这里我需要解释几句。
消息队列产品有很多,比如说常见的有RocketMQ、RabbitMQ、ActiveMQ和Kafka。其中Kafka的性能是最好的,并发量比较大,而且消息收发的速度也非常快。但是消息收发的可靠性上,Kafka不如RabbitMQ,而且技术选型的时候执行速度并不是唯一标准。比速度的话,汇编语言碾压一切高级语言,但是现在我们写程序几乎不会选用汇编语言,而是要兼顾开发效率、易用性和生态圈。RabbitMQ还有另外一个杀手锏,那就是既支持消息异步收发,又支持同步收发,这个太牛了。虽然我们现在大部分的场景对应的是消息异步收发,但是有的场合要支持消息的同步收发,这时候RabbitMQ能适应各种业务场景的优点就显现出来了。所以在项目立项的时候,选择RabbitMQ是最稳妥的方案。
RabbitMQ概念
RabbitMQ是由erlang语言开发的,基于AMQP协议完成的消息队列,是一种应用程序之间通信是一个消息中间件,简单理解就是你发送一个包裹到快递站(RabbitMQ),然后这个快递站把包裹发送到目的地。RabbitMQ知识接收,存储,转发消息数据。
- 可靠性和可扩展性:
- 强调 RabbitMQ 的可靠性特性,如消息持久化和消息确认机制,以确保消息不会丢失。
- 提及 RabbitMQ 的可扩展性,可以通过添加更多的节点和集群来处理大量的消息负载。
- 用途和优点:
- 提到 RabbitMQ 在分布式系统中的常见用途,如异步任务处理、事件驱动架构、微服务通信等。
- 强调 RabbitMQ 的优点,包括可靠性、灵活的路由规则、丰富的功能和社区支持。
AMQP(高级消息队列协议):
AMQP(Advanced Message Queuing Protocol)是一种高级消息队列协议,用于在应用程序之间可靠地传递消息。它是一种开放标准协议,旨在提供统一的消息传递机制,使不同的应用程序或服务能够相互通信。
以下是关于 AMQP 的一些要点:
-
标准化协议: AMQP 是一个标准化协议,由多个参与者共同制定,其中最著名的是 AMQP 0-9-1 版本。该协议定义了消息传递的格式、交换机和队列的行为,以及客户端和代理之间的通信规则。
-
可靠性: AMQP 提供可靠的消息传递机制,确保消息在传输过程中不会丢失。它通过持久化消息、确认机制和事务支持等特性来保证消息的可靠性。
-
灵活的路由: AMQP 提供了灵活的消息路由机制。通过交换机和绑定的组合,可以将消息从生产者路由到一个或多个队列,以满足不同的消息传递需求。支持的交换机类型包括直连交换机、主题交换机、扇形交换机等。
-
消息持久化: AMQP 允许消息进行持久化,即使在代理或系统故障后也能保留消息。这对于对消息传递的可靠性和持久性有重要意义。
-
多种编程语言支持: AMQP 是一种协议,可以在多种编程语言中实现和使用。因此,您可以使用不同的编程语言来开发生产者和消费者,以便在不同的应用程序之间进行消息传递。
-
跨平台和云集成: AMQP 可以在不同的操作系统和云平台上运行。这使得它成为构建分布式系统、微服务架构和云集成的理想选择。
-
消息过期时间: 默认情况消息是无限期存储在Rabbitmq上面的,但是我们可以设置过期时间,到期后无论消息有没有被接受都会删除。
总的来说,AMQP 提供了一个通用的、可靠的消息传递协议,可以促进不同应用程序或服务之间的协作和通信。它的设计目标是支持高性能、可扩展性和可靠性,并且在各种应用场景下得到广泛应用,包括金融服务、电子商务、物联网等。
ACK应答:
消费者接受消息时,必须返回一个Ack应答,Rabbitmq才会认为这条消息接收成功。如果想删除这条消息,消费者发送Ack应答的时候,附带一个deliveryTag标志位就可以了
三种交换机:
直连交换机(Direct Exchange): 直连交换机是最简单的交换机类型之一。它根据消息的路由键(Routing Key)将消息路由到与之完全匹配的队列。当一个队列绑定到直连交换机时,需要指定一个绑定键(Binding Key),当消息的路由键与绑定键完全匹配时,消息会被路由到该队列。
主题交换机(Topic Exchange): 主题交换机根据消息的路由键与主题模式(Topic Pattern)进行匹配,并将消息路由到匹配的队列。主题模式可以使用通配符进行灵活匹配,如使用“*”表示匹配一个单词,“#”表示匹配零个或多个单词。这使得主题交换机能够支持更灵活的消息路由。
扇形交换机(Fanout Exchange): 扇形交换机将消息广播到所有绑定到它的队列,而不考虑消息的路由键。当一个队列绑定到扇形交换机时,所有发送到该交换机的消息都会被复制并发送到该队列。扇形交换机通常用于实现消息的广播机制,将消息发送给所有订阅者。
这些交换机类型提供了不同的路由策略,适用于不同的消息传递需求。根据具体的业务场景和消息的路由规则,您可以选择合适的交换机类型来实现消息的灵活路由和分发。
核心概念:
RabbitMQ 是一个开源的消息代理软件,它提供了一个消息传递系统,用于在不同的应用程序或服务之间交换数据。它基于高级消息队列协议(AMQP)构建,旨在高效处理大量的消息。
RabbitMQ 的核心概念包括以下几个方面:
-
消息代理: RabbitMQ 充当生产者(发送者)和消费者(接收者)之间的中间人。它接收来自生产者的消息,并根据定义的规则将它们路由到相应的消费者。
-
消息: 消息是 RabbitMQ 中的基本单元。它包含要传递的数据以及与该消息相关的元数据。消息可以是任何形式的数据,例如文本、JSON、XML 等。
-
队列: 队列是 RabbitMQ 用于存储消息的容器。当生产者发送消息时,消息首先进入队列,然后等待被消费者处理。队列遵循先进先出(FIFO)的原则,即最先进入队列的消息首先被消费。
-
交换机: 交换机是消息的分发中心,它接收来自生产者的消息并根据预定义的规则将其路由到一个或多个队列中。交换机的类型决定了消息的路由方式,常见的类型有直连交换机、主题交换机、扇形交换机等。
-
绑定: 绑定是交换机和队列之间的关联关系。它定义了消息在哪些队列上进行分发。一个队列可以绑定到一个或多个交换机上,一个交换机也可以绑定到一个或多个队列上。
-
消费者: 消费者是从队列中接收并处理消息的应用程序或服务。它订阅一个或多个队列,并等待消息的到达。一旦有消息可用,消费者就会处理它,并确认消息已经被消费。
通过使用 RabbitMQ,您可以实现不同应用程序或服务之间的松耦合通信。生产者可以将消息发送到 RabbitMQ,而不必关心哪个具体的应用程序或服务会接收这些消息。消费者可以独立于生产者工作,并根据自己的需求从队列中接收消息。
同时,RabbitMQ 还提供了一些高级功能,如消息持久化、消息确认机制、消息优先级等,以及可扩展性和灵活的路由配置,使您能够构建强大而可靠的消息传递系统。
工作原理:
Broker:简单来说就是消息队列服务器实体。
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
producer:消息生产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
生产者发送消息流程:
- 生产者与Broker建立TCP连接
- 生产者与Broker建立通道
- 生产者通过通道消息发送给Broker,由Exchange将消息进行转发
- Exchange将消息转发到指定的Queue
消费者接收消息里流程: - 消费者与Broker建立TCP连接
- 消费者与Broker建立通道
- 消费者监听指定的Queue(队列)
- 当有消息到达Queue时Broker默认将消息推送给消费者
- 消费者接收到消息
- ack回复
同步接收和异步接收
异步:
异步消耗系统的资源较少,但是小程序和后端之间并不是长连接,所以后端项目异步方式接收到队列中的消息无法推送给移动端的小程序。小程序自带的消息推送机制,但是这个功能是有严格限制的,有效期和推送次数做了限制。
同步:
可以通过java后端项目采用同步的方式接收队列中的消息。在移动端,我们创建定时器,然后向后端java项目发出轮询请求。后端java项目接收到轮询请求后,用同步的方式接收消息队列中的消息,然后把消息队列存储在MongoDB上面,最后向小程序返回接收了多少条新消息,移动端则弹出提示框告知用户消息的消息通知
三.五种消息模型:
简单模式
一个生产者只能对应一个消费者,中间用队列连接
work工作模式
多个消费者去消费队列里的消息,但是队列里的消息只能被一个消费者消费,多部署几个消费者,就可以缓解压力。
发布/订阅(pub/sub)模式
假如我们有一个国家气象局天气预报系统,这个时候他发送消息,其他的服务商,比如百度、网易、腾讯等公司都要从国家天气预报系统那里获取天气怎么办呢?总不能百度获取了今天的天气其他公司就获取不了天气了吧,或者让国家天气预报系统给每个服务商都发送一次消息,那样显然是很麻烦的。
所以我们需要用到一个Exchange交换机角色来帮助我们把消息发给所有订阅我们的服务商。
Routing路由模式
路由模式不是给所有订阅他的队列发消息,而是根据路由键来确定给那个队列发消息,队列和交换机绑定时通过路由键,而生产者发消息时也需要指定路由键,这样就确定给那个队列发消息了。
Topics通用模式
生产者将消息发送到Topic交换机,交换机按照复杂的给咱,把消息路由到某个队列中