消息队列——面试(来自黑马程序员的视频)

 

目录

1 为什么使用消息队列

解耦——高内聚,低耦合

异步

同步调用带来的问题

使用MQ的异步调用

使用的场景和条件

流量削峰

无MQ时,面对大流量

MQ流量削峰

流量削峰的经济考量

2 各种消息队列产品的比较

3 消息队列的优点和缺点

系统可用性

系统复杂度提高

一致性问题

4 如何保证消息队列的高可用——集群(多个节点)

RabbitMQ高可用——普通集群

RabbitMQ高可用——镜像集群

RocketMQ高可用——双主双从

5 如何保证消息不丢失

消息丢失的原因

确保消息不丢失方案

6 如何保证消息不被重复消费

消息重复的原因

保证消息消费的幂等性——只在消费方处理

7 如何保证消息消费的顺序性

消息的顺序性消费



1、为什么使用消息队列?

2、各种消息队列产品比较?

3、消息队列的优点和缺点?

4、如何保证消息队列的高可用?

5、如何保证消息不丢失?

6、如何保证消息不被重复消费?

7、如何保证消息消费的顺序性?

8、基于MQ的分布式事务实现

1 为什么使用消息队列

消息队列是一种“先进先出”的数据结构

多用于分布式场景中,用消息队列来传递数据

常见的应用场景:解耦、异步、削峰

多用于分布式场景中,用消息队列来传递数据

(1)数据以消息的形式封装起来,然后把这个数据放入到消息队列中

(2)消息的消费方会监听MQ,然后从消息队列中取消息

解耦——高内聚,低耦合

系统的耦合性越高,容错性就越低。——中间层的出现就起到解耦的作用。

RPC的调用方式:耦合度高,直接调用

                                          订单系统
支付系统 库存系统 物流系统

订单系统耦合调用库存系统、支付系统、物流系统,任何一个子系统出现故障或者因为升级原因暂时不可用,都会造成下单操作异常,影响用户体验

 

使用消息队列解耦合

订单系统
消息队列(存储着各个子系统需要处理的数据)
支付系统 库存系统 物流系统

订单系统将自己的工作做完,然后将子系统需要处理的数据以消息的形式发送给MQ。子系统监听MQ,取出消息。

此时,如果物理系统发生故障,需要几分钟恢复,在这段时间内,物流系统要处理的数据被缓存到消息队列中,用户的下单操作正常完成。

当物流系统恢复后,补充处理存在的消息队列中的订单消息即可。

终端系统感知不到物流系统发生过几分钟故障。

 

异步

同步调用带来的问题

消息队列——面试(来自黑马程序员的视频)_第1张图片

用户向系统A发起一个请求。

A接收到请求,需要本地写库,还需要B、C、D三个系统写库。

A要3ms,B要300ms,C要450ms,D要953ms,总延迟953ms。延迟太长。——这里应该是依次写库,不是并发执行

使用MQ的异步调用

 

消息队列——面试(来自黑马程序员的视频)_第2张图片

A系统连续发送3条消息到MQ队列中,假如耗时5ms,A系统从接收一个请求到返回响应给用户,总时长是3+5=8ms,大大提升了响应度,改善了用户的体验。

???——这里返回给用户的结果是什么呢?如果在系统处理消息的过程中发生了错误,导致消息丢失怎么办,此时之前返回给用户的结果是否是正确的呢?

PS:如果返回给用户的数据需要依赖B、C、D处理的结果,这个架构是不适用的。

 

使用的场景和条件

如果对用户的响应需要依赖于下游的系统的处理结果,那么这种业务MQ并不使用。

如果对用户的响应与下游的系统的处理结果无关,那么适用MQ。

 

流量削峰

无MQ时,面对大流量

消息队列——面试(来自黑马程序员的视频)_第3张图片

应用系统如果遇到系统请求流量的瞬间猛增,有可能会将系统压垮。

有了消息队列可以将大量请求缓存起来,分散到很长一段时间处理,这样可以大大提升系统的稳定性和用户体验

MQ流量削峰

消息队列——面试(来自黑马程序员的视频)_第4张图片

为了保证系统的稳定性,如果系统负载超过阈值,就会阻止用户请求,这回影响用户体验。

使用消息队列将请求缓存起来,等待系统处理完毕后通知用户下单完毕,这样比总不能下单体验要好。

A系统作为消息的消费方,可以对消息的处理进行限流——比如一次只处理2k条

流量削峰的经济考量

对于以上MQ

业务系统正常时段的QPS如果是1000,流量最高峰是10000,为了应对流量高峰配置高性能服务器显然不划算。

这时可以使用消息队列对峰值流量削峰

2 各种消息队列产品的比较

特性 ActiveMQ RabbitMQ RocketMQ kafka
开发语言 java erlang java scala
单机吞吐量 万级 万级 10万级 10万级
时效性 ms us ms ms
可用性 高(主从架构) 高(主从架构) 非常高(分布式架构) 非常高(分布式架构)
功能特性 成熟的产品;有较多的文档;各种协议支持较好 基于erlang开发,并发能力强,性能好,延迟低;管理界面丰富 MQ功能更比较完备,扩展性佳 只支持主要的MQ功能(消息查询,消息回溯等功能么有提供),在大数据领域应用广。

 

 

3 消息队列的优点和缺点

面试官的心理:在当前项目中引入了消息队列后,对你本身的架构的影响

缺点:

    (1)系统可用性降低

    (2)系统复杂度提高

    (3)一致性问题

系统可用性

系统引入的外部依赖越多,系统稳定性越差。

一旦MQ宕机,就会对业务造成影响。

——————解决方法:保证MQ的高可用性。如果保证MQ的高可用性????

系统复杂度提高

MQ的加入大大增大了系统的复杂度,以前系统间是同步的远程调用,现在是通过MQ进行异步调用。

——————消息丢失怎么办?重复消息怎么处理?如何保证消息传递的顺序性(消费的顺序和发送的顺序一致)?

一致性问题

A系统处理完业务,通过MQ给B、C、D三个系统发消息数据,如果B系统、C系统处理成功,D系统处理失败。怎么办?

——————如何保证消息数据处理的一致性(分布式事务——二次提交,回滚)?

4 如何保证消息队列的高可用——集群(多个节点)

面试官对于MQ的加入对项目系统可用性的影响,希望你给出解决方案,只需要给出一个即可。

RabbitMQ高可用——普通集群

消息队列——面试(来自黑马程序员的视频)_第5张图片

1、在多台机器上分别启动RabbitMQ实例

2、多个实例之间可以相互通信

3、创建的Queue只会放在一个RabbitMQ上,其他实例都同步元数据

4、消费的时候,如果连接的没有Queue,那么当前实例会从Queue所在实例拉取数据

————元数据:可以理解为Queue的配置信息,可以通过元数据找到Queue的位置

特点:没有真正做到高可用;有数据拉取的开销和单实例的瓶颈问题

RabbitMQ高可用——镜像集群

 

消息队列——面试(来自黑马程序员的视频)_第6张图片

1、在多台机器删分别启动RabbitMQ实例

2、多个实例之间可以相互通信

3、每次生产者写消息到Queue的时候,都会自动把消息同步到多个实例的Queue上。每个RabbitMQ节点上都有Queue的消息数据和元数据。

4、某一个节点宕机,其他节点依然保存完整数据,不影响客户端消费

RocketMQ高可用——双主双从

消息队列——面试(来自黑马程序员的视频)_第7张图片

黄色为主节点;蓝色为从节点。从节点不能接收消息。

1、生产者通过Name Server发现Broker(存储数据)

2、生产者发送队列消息的2个Broker主节点

3、Broker主节点分别和各自从节点同步数据

4、消费者从主或者从节点订阅消息

Producer集群生产消息,首先发送消息到Name Server,询问Broker的地址。然后,Producer集群再给Broker发送生产的消息。

Broker到Name Server之间的箭头:Broker会发送心跳(ping/ICMP之类报文)到Name Server,说明自己在线。

 

5 如何保证消息不丢失

1、消息丢失的原因?

2、如何保证消息不丢失?

消息丢失的原因

情况1:消息生产者没有成功发送到MQ Broker。——源端

情况2:生产者间消息发送到MQ Broker后,Broker还没有存到硬盘的时候宕机了。此时消息在内存中,还未持久化,此时MQ宕机,则消息丢失。——中间

情况3:消息者获取到消息,但消费者还没有来得及处理宕机了,但此时MQ中消息已经删除了,消费者重启之后,不能再消费之前的消息。——终端

确保消息不丢失方案

1、消息发送者发送给MQ Broker后,MQ Broker给生产者确认收到。如果没有收到确认,则再次发送。——源端,确认重发

2、MQ收到消息后进行消息持久化。——中间,持久化(如果此时还没来得及持久化就宕机,则消息丢失。此时仍然后集群可以保证不丢失。)

3、消费者收到消息,处理完毕后,手动进行ACK确认。——终端,发送确认

4、MQ收到消费者ACK确认后,删除持久化的消息

6 如何保证消息不被重复消费

当出现了重复消息后,为了保证系统数据的正常性,就必须保证幂等性

1、重复消息产生的原因

2、保证消息幂等性的方案

幂等性:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。https://blog.csdn.net/miachen520/article/details/91039661

消息重复的原因

消息重复的根本原因:网络不可达

消息重复发生在两次消息传输的确认应答未收到

1、发送时消息重复

当一条消息已成功发送到服务端,此时出现网络中断,导致服务端对客户端的确认应答失败。

此时消息生产者认为消息发送失败,并再次发送消息,消费者后续会受到两条内容相同的消息。

2、消费时消息重复

消费者处理消息完毕,向MQ发送应答,但此时网络中断,导致MQ没有收到确认。

此时,MQ由于没有收到确认,消息持久化并没有删除,会再次发送同一消息给消费方。

保证消息消费的幂等性——只在消费方处理

1、消费者发送消息时携带一个全局唯一的消息ID——同一业务的所有消息,ID相同,顺序号不同。和TCP/IP网络协议一样。

2、消费者获取消费后,先根据ID在Redis DB中查询是否存在消费记录

3、如果没有消费过就正常消费,消费完毕后写入Redis DB

4、如果消息消费过就直接舍弃

 

7 如何保证消息消费的顺序性

1、什么是消费顺序消费?

2、确保消息顺序消费的方案

消息的顺序性消费

消息有序指的是可以按照消息的发送顺序来消费

例如:一笔订单产生了3条消息,分别是订单创建、订单付款、订单完成。消费时,要按照顺序依次消费才有意义。与此同时多笔订单之间又是可以并行消费的。

确保消息顺序消费

生产者:MQ Server:消费者 = 1:1:1

消息队列——面试(来自黑马程序员的视频)_第8张图片

可以保证顺序性,但是由于是全局的顺序消费,无法并行

比如业务1:M1,M2,M3;业务2:S1,S2,S3。——同一业务的所有消息持有相同的ID。

此时只能等业务1处理完,才能处理业务2

容错性降低

局部顺序消费

消息队列——面试(来自黑马程序员的视频)_第9张图片

1、生产者根据消息ID将同一组消息发送到同一个Queue中。

2、多个消费者同时获取Queue中的消息进行消费

3、MQ使用分段锁(不是全局锁)保证单个Queue中的有序消费——消费者处理M1时MQ Server锁住Queue1,M1被消费者1处理完毕,发送确认MQ Server收到后,把Queue1解锁;此时消费者2处理M2

算法:

    通过ID选择一条队列

    将ID对Queue的Size取模,此时索引值就对应这个ID消息

    可以根据ID获取消息

8 基于MQ的分布式事务

分布式事务就是为了保证不同数据库的数据一致性。

消息的发送方先处理自己的任务,然后将消息存储,消息的状态置位;然后向MQ发送消息。

消息消费方从MQ拉取消息,然后将消息处理并存储到本,然后向MQ发送消息;

消息发送方从MQ拉取消息, 如果消费方处理成功则将消息装填置位,数据一致性成功。

使用MQ使得消息的消费方和消息的生产方可以通信,以此来沟通消息最终处理的状态。

当一边处理成功,另一边处理失败时,则回滚或者重新发送消息,直到处理成功。

 

 

 

 

 

 

 

 

你可能感兴趣的:(#,C++)