• 经典面试题 之 MQ


    1.为什么使用MQ?

    使用MQ的好处:解耦,异步,削峰平谷

    解耦:

    当A系统生产关键数据,而且B,C,D系统需要A系统给它们发送数据,来进行下一步操作,此时A系统和BCD系统产生了严重的耦合,所有的操作和维护都要在A系统中进行,如果将A系统产生的数据放到MQ当中,让BCD系统需要的时候去消费,此时就解放了A系统,不用考虑调用成功,失败超时等情况,同时ABCD系统独立运行,后续新添加系统需要A系统的数据,也不需要去修改A系统的代码,达到了解耦的效果

    异步:

    一般互联网类企业,对用户的直接操作,一般要求每个请求在200ms以内完成。对于一个系统调用多个系统,在不适用mq的情况下,它执行完返回的耗时,是执行完所有系统所需时间的总和;使用mq进行优化后,执行的耗时,则是执行主系统的耗时,以及加上主系统发送数据到消息队列的耗时,大幅度提升高延时接口的性能,提升了用户体验.

    削峰平谷:

    一般MySQL的每秒请求最高在2000左右,用户访问量高峰期的时候涌入的大量请求,很可能将MySQL给打死,然后系统就挂掉,但是高峰期过了,请求量可能远远低于2000,所以这种情况去增加服务器就不值得,如果使用mq的情况,将用户的请求全部放到mq中,然后让系统去消费用户的请求,不要超过系统所能承受的最大请求数量,保证系统不会再高峰期挂掉,但此时可能有几十万或几百万请求积压在mq中,但是高峰期一过,系统还是按照最大请求数量进行处理请求,很快就能将积压请求处理完

    使用MQ的缺陷:

    • 系统可用性降低:以前只要担心系统的问题,现在还要考虑mq如果挂掉的问题,因为mq一旦挂掉,所关联的系统,就会统统挂掉
    • 系统复杂性变高:考虑的问题变多,要考虑消息丢失,消息重复消费的情况
    • 一致性问题:比如A系统调用BCD系统,BCD同时成功才能执行成功,返回数据,现在BC执行成功,D发生异常的情况,并没有执行成功,但是A给用户返回的是成功

    2.你了解哪些MQ技术,ActiveMQ,RabbitMQ,RocketMQ,kafka

    • ActiveMQ它可以支持万级的吞吐量,它是一个比较成熟完善的中间件,但是它存在有少量信息丢失的情况,而且目前官方对他的更新迭代不是很即时,社区的活跃度不是很高
    • RabbitMQ是一款用Erlang语言开发的消息中间件,它延时低,唯一一款达到微妙级延时的消息中间件,而且社区活跃度高,对于bug问题的修复很及时,而且提供了很友善的后台界面,唯一的劣势是就是我们搞java开发的很少有人能够阅读它的源码,对于问题的修复仅仅依靠社区。
    • RocketMQ是阿里旗下的一款品质优秀的MQ,它可以达到十万级的吞吐量,而且它还是支持分布式事务,应用于分布式架构,它的维护基本上都是靠阿里,如果哪天阿里宣布放弃这个项目的维护,除非你们公司有能力继续来维护RocketMQ的使用。
    • Kafka也是一款分布式的中间件,最大优点就是其吞吐量高,一般运用于大数据系统的实时运算和日志采集的场景,功能简单,可靠性高,扩展性高,唯一的缺点是可能导致重复消费,但是这点轻微的影响在大数据场景下可以忽略。

    3.RabbitMQ 的使用场景有哪些?

    抢购活动,削峰填谷,防止系统崩塌。

    延迟信息处理,比如 10 分钟之后给下单未付款的用户发送邮件提醒。

    解耦系统,对于新增的功能可以单独写模块扩展,比如用户确认评价之后,新增了给用户返积分的功能,这个时候不用在业务代码里添加新增积分的功能,只需要把新增积分的接口订阅确认评价的消息队列即可,后面再添加任何功能只需要订阅对应的消息队列即可。

    4.如何保证MQ的高可用?

    非分布式的MQ的高可用:

    普通集群模式:实际queue保存在一个节点上,其他节点保存该queue的元数据,消费者连接某个节点,该节点去调用实际存放queue的节点,返回数据,说白了只是简单的提高了吞吐量而已.

    缺陷在于:在集群内部产生大量的数据传输,高可用性没有,queue所在的节点宕机,服务就没法继续使用

    镜像集群模式:每个节点上都保存了实际的queue的全部数据,消费者无论连接哪个节点,都能直接获取到数据.任何一个节点宕机,其他节点还存在queue的全部数据,消费者换个节点继续消费,这是高可用的模式

    分布式MQ的高可用:

    假设生产者往topic里写了三条数据,每条数据放在一个partition中,每个partition部署在一台机器中,每个partition都有一个或多个replica副本,其中有一个是leader,其他的是follower,只有leader能够向外提供数据的读写,生产者写入消息时,leader负责向follower同步消息,此时高可用架构就已经体现,如果一台leader宕机,会从它的follower中选举一个leader,继续向外提供服务

    5.如何保证消息不被重复消费(如何保证消息消费时的幂等性)?

    重复消费:

    每个中间件它能够保证的是消息不丢失,但不能保证消息不被重复发送,所以接收方就要做幂等性的判断,防止消息重复消费,例如:支付金额的消息被消费了两次,那么所得到的钱数就是错误的,这种情况在系统中肯定是不允许存在的。

    消费的幂等性(同样的操作,在一段时间内,只执行一次):

    如果是往数据库里写入数据,就根据主键查一下,如果数据已经存在,就update

    可以在把数据先存在set或者redis中,消费前,先去里面查看,数据是否已存在,已存在就丢弃这数据,比如说我们的订单系统,生成订单也会用到mq,此时订单id就是全局唯一的id,在写入数据库之前,就可以先把数据去redis中查询,如果redis中已经存在,则不进行消费操作,如果redis中不存在的话,就存在redis中,然后进行下一步操作.

    在数据库中设置唯一约束,就不会导致重复数据的多次插入

    6.如何保证消息不丢失

    rabbitMQ:

    消息丢失的情况:生产者写的消息在到中间件的网络传输过程中就丢了,或者是消息到了中间件,但是内部出错,消息没保存下来

    中间件将消息保存下来,还没等到消费者消费完,就自己挂掉,导致消息丢失

    消费者取到消息还没来得及消费就自己挂掉了,因为rabbitMQ消费者开启了autoAck,在消费数据还没成功时,就已经向中间件发送完成的信息,此时消费者挂掉,就会消息丢失   

    解决方案:

    生产者消息丢失,可以通过开启事务功能,如果消息没有发送成功,发生异常就回滚,然后重试发送消息,发送成功就提交事务,这个的缺陷就是阻塞式的,降低吞吐量,耗费性能;如果是rabbitMQ可以开启confirm模式,它能给每次写的消息都分配一个唯一的id,如果写入到rabbitMQ中,rabbitMQ就会回传一个ack消息,如果没有就会会挑一个nack接口,告诉你消息接收失败,你可以重试,confrim机制是异步的,效率会高很多

    关于中间件的数据丢失,可以开启中间件的持久化,将消息持久化磁盘中,中间件挂了恢复之后自动读取之前存储的数据.

    消费者数据丢失,关闭rabbitMQ的autoACK机制,自己手动提交完成信息

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

    rabbitMQ为多个消费者开辟多个queue队列(先进先出),将保证操作顺序的消息发布到同一个队列中去,操作这个队列的消费者会一个一个消息去处理,因为队列这种结构是先进先出的类型,所以保证的数据的顺序性。

    8.消息大量积压怎么解决?

    • 临时启动多个消息者,并发处理消息
    • 临时启动多个消息者,接受消息之后,不处理。暂时把消息写到文件中。消息中间件中的消息处理的完了。关闭临时消费者。单独写个离线程序,处理文件中的消息 
    • 临时启动多个消息者,接受消息之后,直接丢弃。 可以让生产者的源头恢复数据

    9.RabbitMQ 节点的类型有哪些?

    磁盘节点:消息会存储到磁盘。

    内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。

    10.rabbitmq如何确认消息一定发送到了消息中间件中呢?

    消息发送到server是先通过交换机,再到消息队列,只要数据到队列,那么此消息肯定是发送成功的.

    第一步确定消息发送到了交换机.

    使用发送方确认机制来判断消息是否发送成功.

    第二步确认交换机把消息路由到消息队列.

    使用失败回调来判断消息是否发送成功.   

    只有两步都成功,此消息才是发送成功的.

    11.rabbitmq的集群

    集群分为普通集群和镜像集群.

    普通集群:

    普通集群,他会把所有节点的交换机信息和队列的元数据分为两种(队列数据分为两种: 一种为队列里面的消息,另一种是队列本身的信息, 后者被称为元数据.)进行复制,确保所有的节点都有一份.

    镜像集群:

    在普通集群的基础上,把所有的队列数据完全同步(对性能有一定的影响)当对数据可靠性要求高时,可以使用镜像模式.

    镜像集群实现有两种方式:   一种是直接在管理台控制,一种是在声明队列的时候控制.

    配置集群还设计到节点信息, 有内存节点和磁盘节点,如果对队列有修改的情况下,必须有磁盘节点,用来保存信息,内存节点断电后,信息就消失,无法保存. 默认就是磁盘节点, 设置 --ram为内存节点.

  • 相关阅读:
    html2canvas图片跨域问题
    电信保温杯笔记——《统计学习方法(第二版)——李航》第17章 潜在语义分析
    CSB ---> (XXE)XML基础
    Mysql通过Canal同步Elasticsearch
    “12306” 的架构到底有多牛逼?
    超精准!AI 结合邮件内容与附件的意图理解与分类!
    4 轮拿下字节 Offer,面试题复盘
    微信小程序之首页-后台交互及WXS的使用
    2023-09-18 LeetCode每日一题(打家劫舍 III)
    温故而知新七(C++)
  • 原文地址:https://blog.csdn.net/weixin_69413377/article/details/126327881