## 1. 什么是是MQ
mq是一个消息队列,其主要目的是为了解决传统的消息传输上管理困难,效率不高的问题.
mq有三大优点:解耦,异步,削峰。
### 1.1 解耦: 如果是传统的消息通讯方式,无论是哪一方都要去维护一份供外部通讯的这个一个接口,而且各方处理消息的能力有限,效率上明显跟不上,并且这样子二者之间的耦合度非常高,对于拓展管理方面极不友好,而是要了mq就不一样,发送方只需要将消息发送给mq就可以了,别的不用考虑,接口什么的由mq去维护,接收方也只需要去mq里消费消息就可以了,就需要其他开销,一切由mq中间件来做,达到了解耦操作.
### 1.2 异步: 使用mq,还可以达到异步效果,极大地提升了消息传输的效率.发送方在发送消息后不需要关心消费方是否能消费完成,还可以继续发送其他消息.
### 1.3 削峰:如果是传统的消息通讯,一下子有大量的消息发送给接收方,这样对于接收方的处理压力是很大的,而我们刚好可以利用mq达到一个缓冲操作,一旦流量超出了接收方处理范围,不用担心,只需要慢慢消费即可,像经典的双十一,就很容易会使用到mq这么一个优点.
虽然mq有三大优点,但是我们还是得关心其一些缺点:
因为增加了中间件,系统复杂度肯定大大提高,增加了很多维护的成本,比如我们要保证消息不丢失(一致性)和消息幂等性问题,还要保证mq的高可用等.
## 2. MQ有什么缺点?
### 2.1 系统可用性降低
系统引入的外部依赖越多,越容易挂掉,本来你就是A系统调用BCD三个系统的接口就好了,人 ABCD四个系统好好的,没啥问题,你偏加个MQ进来,万一MQ挂了咋整?MQ挂了,整套系统崩溃了,你不就完了么。(可以利用集群解决)
### 2.2 系统复杂性提高
硬生生加个MQ进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已。
### 2.3 一致性问题(保证消息不丢失)
A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,咋整?你这数据就不一致了。
所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,最好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了10倍。但是关键时刻,用,还是得用的。
## 3. MQ的应用场景
### 3.1 异步处理
场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种1.串行的方式;2.并行方式。
(1)串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。(架构KKQ:466097527,欢迎加入)
(2)并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。
假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。
因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)。
小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?
引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:
按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。
### 3.2 应用解耦
场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图:(架构KKQ:466097527,欢迎加入)
传统模式的缺点:
1) 假如库存系统无法访问,则订单减库存将失败,从而导致订单失败;
2) 订单系统与库存系统耦合;
如何解决以上问题呢?引入应用消息队列后的方案,如下图:
订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦。
### 3.3 流量削峰
流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
可以控制活动的人数;
可以缓解短时间内高流量压垮应用;
用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面;
秒杀业务根据消息队列中的请求信息,再做后续处理。
### 3.4 日志处理
日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。架构简化如下:
日志采集客户端,负责日志数据采集,定时写受写入Kafka队列;
Kafka消息队列,负责日志数据的接收,存储和转发;
日志处理应用:订阅并消费kafka队列中的日志数据;
(1)Kafka:接收用户日志的消息队列。
(2)Logstash:做日志解析,统一成JSON输出给Elasticsearch。
(3)Elasticsearch:实时日志分析服务的核心技术,一个schemaless,实时的数据存储服务,通过index组织数据,兼具强大的搜索和统计功能。
(4)Kibana:基于Elasticsearch的数据可视化组件,超强的数据可视化能力是众多公司选择ELK stack的重要原因。
## 4. Rabbitmq是什么?Rabbitmq的构造
(1)生产者Publisher:生产消息,就是投递消息的一方。消息一般包含两个部分:消息体(payload)和标签(Label)
(2)消费者Consumer:消费消息,也就是接收消息的一方。消费者连接到RabbitMQ服务器,并订阅到队列上。消费消息时只消费消息体,丢弃标签。
(3)Broker服务节点:表示消息队列服务器实体。一般情况下一个Broker可以看做一个RabbitMQ服务器。
(4)Queue:消息队列,用来存放消息。一个消息可投入一个或多个队列,多个消费者可以订阅同一队列,这时队列中的消息会被平摊(轮询)给多个消费者进行处理。
(5)Exchange:交换器,接受生产者发送的消息,根据路由键将消息路由到绑定的队列上。
(6)Routing Key: 路由关键字,用于指定这个消息的路由规则,需要与交换器类型和绑定键(Binding Key)联合使用才能最终生效。
(7)Binding:绑定,通过绑定将交换器和队列关联起来,一般会指定一个BindingKey,通过BindingKey,交换器就知道将消息路由给哪个队列了。
(8)Connection :网络连接,比如一个TCP连接,用于连接到具体broker
(9)Channel: 信道,AMQP 命令都是在信道中进行的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接,一个TCP连接可以用多个信道。客户端可以建立多个channel,每个channel表示一个会话任务。
(10)Message:消息,由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。
(11)Virtual host:虚拟主机,用于逻辑隔离,表示一批独立的交换器、消息队列和相关对象。一个Virtual host可以有若干个Exchange和Queue,同一个Virtual host不能有同名的Exchange或Queue。最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段
## 5. vhost 是什么? 起什么作用?
每一个rabbitmq服务器都能创建虚拟的消息服务器,我们称之为虚拟主机(virtual host)。简称vhost
特性:
每一个vhost本质上是一个小型的独立的rabbitmq服务器,拥有自己独立的完整的一套队列、绑定关系、交换器等。同一个服务器上的多个vhost是完全隔离的。队列及交换器等不互通。
所以一个broker可以开设多个vhost,用于不同用户的权限分离
如何创建vhost?
1)通过前台页面的admin中创建
2)使用rabbitmqctl add_vhost vhost名称 命令
如何删除vhost?
1)前台删除
2)rabbitmqctl delete_vhost vhost_name
## 6. 谈谈你对AMQP的理解
AMQP协议是什么?
AMQP协议,所谓的高级消息队列协议,可以把它理解成一种公认的协议规范,就像http协议一样,只是这个AMQP协议针对的是消息队列。这个协议使得遵从了它的规范的客户端应用和消息中间件服务器的全功能互操作成为可能。
了解下AMQP协议的基本概念
Broker:用于接受信息和分发信息的应用。
Virtual hosts:在一个Broker上面划分出多个隔离的环境,这多个环境就可以理解成是Virtual hosts,就像使用虚拟机一样,每个虚拟机之间都有完整的组件,各Virtual hosts下的用户、交换器以及队列等互不影响,这样方便不同的业务团队在使用同一个Rabbit server提供的服务时,能够划清界限。
Connection:消息生产者和消息消费者还有Broker之间的TCP连接,如果要断开连接,只会在客户端断开,而
Broker不会断开连接,除非网络出现了故障或者Broker服务出了问题。
Channel:通道,如果每一次访问消息队列中间件都建立一个TCP连接的话,那么系统资源会被大量的占用,效率也会降低,所以AMQP提供了Channel机制,共享同一个TCP连接,而一个TCP连接里可以有大量的Channel。假设如果有多个线程访问消息队列中间件服务,每个线程通常都会有自己单独的Channel来做通信,而每个Channel会有自己的Channel id,这样客户端和Broker就能够互相识别Channel,所以Channel之间是完全隔离的。
Exchange:交换机,这是消息到达Broker的第一站,由于Exchange和Queues之间有绑定键来确定双方发送消息的匹配规则,所以这时Exchange会根据消息的路由键和自己的类型,来匹配绑定规则,将消息分发到对应的Queues上。
Queue:队列,消息所到达的最终站,消费者从这里拿消息做消费。
Binding:可以把它理解成一个虚拟的连接,定义了Exchange和Queues之间的匹配规则,只有匹配这个规则的交换机里的消息才会被发送到这个队列里,不过如果消息没法找到匹配的队列的话,那么,根据该条消息的属性,这个消息要么被丢弃,要么返回生产者那里。
Exchange的类型
这里把Exchange和Queues之间的匹配规则称之为绑定键。
类型 说明
direct(直连) 消息的路由键要和绑定键一模一样才能分发到队列
fanout(广播) 无需绑定键,只要有和这个交换机做绑定的队列,都会收到消息,有点类似发布-订阅
topic(主题) 这个类型的交换机要求消息路由键和绑定键要模糊匹配才能分发,以.号来分割每个词, #号代表匹配多个词,*号代表匹配只一个词
headers(header属性) 这种类型的交换机不再是基于路由键了,而是基于消息中的header属性,只有消息中header属性的值与绑定键相同时,消息才会被分发到相应的队列中
默认交换机 如果不指定上述的交换机类型,就会使用默认的direct类型,同时绑定键默认是队列名,所以消息会分发到与路由键同名的队列里
## 7. 消息是如何路由的?
消息提供方->路由->一至多个队列消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。通过队列绑定键,可以把队列绑定到交换器上。消息到达交换器后,RabbitMQ 会将消息的路由键与队列的绑定键进行匹配(针对不同的交换器有不同的路由规则);
常用的交换器主要分为一下三种(广播模式):
fanout:如果交换器收到消息,将会广播到所有绑定的队列上
direct:如果路由键完全匹配,消息就被投递到相应的队列
topic:可以使来自不同源头的消息能够到达同一个队列。 使用 topic 交换器时,可以使用通配符
————————————————
原文链接:https://blog.csdn.net/weixin_47303191/article/details/124693751