当前位置: 首页 > 科技观察

面试杀手:为什么一定要用MQ中间件?

时间:2023-03-19 17:34:24 科技观察

本文将为大家讲述消息中间件的高频面试题,同时涵盖MQ中间件的一些常见技术问题。如果面试官看到你在简历中写了MQ中间件经验,可能会有以下问题:你们公司生产环境用的是什么消息中间件?为什么在系统架构中引入消息中间件?介绍一下message中间件的优缺点是什么?好吧,让我们一一分析吧!你们公司的生产环境用的是什么消息中间件?首先,你可以告诉我们你的公司选择了什么样的消息中间件,比如使用的是RabbitMQ,然后我可以给你初步分析一下不同MQ中间件技术的选择。举个例子:比如ActiveMQ就是一个老牌的消息中间件。国内很多公司过去用的很广泛,功能也很强大。但问题是ActiveMQ能否支持互联网公司高并发、高负载、高吞吐的复杂场景,目前还无法确认,在国内互联网公司实现的也很少。而且一些传统企业更多的是使用ActiveMQ来进行异步调用和系统解耦。然后就可以说说RabbitMQ了,它的优点是可以支持高并发、高吞吐、高性能,并且有非常完善和方便的后台管理接口使用。另外还支持集群,高可用部署架构,高可靠消息支持,功能比较齐全。而且,经过调研,国内各大互联网公司部署大型RabbitMQ集群支撑自身业务的案例很多,国内也有不少中小型互联网公司在使用RabbitMQ。另外,RabbitMQ的开源社区非常活跃,使用频率更高的迭代版本修复发现的bug,进行各种优化。因此,经过综合考虑,公司采用了RabbitMQ。但是RabbitMQ也有一个缺陷,就是它是基于Erlang语言开发的,所以很难对里面的源码进行分析,也很难进行深入的源码定制和改造。毕竟需要扎实的Erlang语言基础。然后我们可以说说阿里开源的RocketMQ。通过了阿里生产环境超高并发、高吞吐的测试。性能优异,支持分布式事务等特殊场景。而且RocketMQ是基于Java语言开发的,适合深入阅读源码。如有需要,可在源码层面解决线上生产问题,包括对源码的二次开发和改造。另一个是卡夫卡。Kafka提供的消息中间件的功能明显少了很多,比上面提到的MQ中间件要少很多。但Kafka的优势在于,它是专门针对超高吞吐实时日志采集、实时数据同步、实时数据计算等场景设计的。因此,在大数据领域,Kafka常与实时计算技术(如SparkStreaming、Storm、Flink等)结合使用。但是在传统的MQ中间件使用场景中很少使用。PS:如果你没有在自己的电脑上部署过上面的一些MQ技术,也没有写过几个helloworld的经验,建议自己去各个技术的官网找helloworld的demo,自己运行一下。为什么要在您的系统架构中引入消息中间件?要回答这个问题,先说说消息中间件的常见使用场景。然后结合自己系统对应的使用场景,说说自己的系统引入消息中间件解决了哪些问题。系统解耦假设你有一个系统A,这个系统A会产生一个核心数据,现在下游有系统B、C需要这个数据。很简单,A系统只是调用B系统和C系统的接口,向它们发送数据。整个过程如下图所示:但是现在如果有系统D、系统E、系统F、系统G等等,其他十几个系统会逐渐需要这个核心数据吗?如下图所示:大家不要以为这是在开玩笑。一个大型系统往往拆分成几十个甚至上百个子系统,每个子系统对应N个以上的服务。这些系统之间存在错综复杂的关系网络。如果一个系统产生了一个核心数据,那么无数其他下游系统可能需要这个数据来实现各种业务逻辑。这时候如果你采用上面的模型来设计系统架构,那你负责系统A的同学肯定会烦死的。先是来了一个人,让他给一个新的系统H发数据,系统A的同学只好修改代码,然后在那个代码里面加上调用新系统H的过程。过了一会儿,系统B是一个即将下线的旧系统。告诉A系统的同学:不要给我发数据,然后A系统又修改了代码,不再发给B系统了,那万一下游系统突然宕机了怎么办?系统A的调用代码会不会抛出异常?那么A系统的同学就会收到一个告警,说有异常,结果他要关心下游是哪个系统宕机了。因此,在实际的系统架构设计中,如果全部采用系统耦合的方式,在某些场景下是绝对不合适的,系统耦合度太严重了。并且相互之间的耦合并不是核心环节的调用,而是一些非核心场景(比如上面提到的数据消费)导致系统耦合,会严重影响上下游系统的开发和维护效率。因此,在上述系统架构中,可以使用MQ中间件来实现系统解耦。系统A将自己的核心数据发送给MQ,任何有兴趣的下游系统都可以自己消费,不需要就取消数据消费,如下图:异步调用假设你有一个系统调用环节,系统A调用系统B,一般需要20ms;系统B调用系统C,一般需要200ms;系统C调用系统D,一般需要2s,如下图:现在最大的问题是:一个用户的请求特别慢,因为完成一个链接需要20ms+200ms+2000ms(2s)=2220ms,这超过2秒。但实际上,链路中系统A调用系统B,系统B调用系统C,两步耗时220ms。因为引入了系统C调用系统D的步骤,导致最终链接执行时间超过2秒,直接降低了10倍的链接调用性能。这就是导致链接执行过慢的罪魁祸首。这时候我们可以想一下,是不是可以把系统D从链接中提取出来,进行异步调用呢?其实很多业务场景是可以允许异步调用的。比如你平时点外卖,点击下单然后付款。这时候扣款,创建订单,通知商家给你准备菜品。接下来是不是需要找骑手给你送餐?寻找骑手的过程需要一套复杂的算法来实现调度,非常耗时。但其实晚点几十秒完成骑手派遣是可以的,因为其实没必要一付款就马上给你找好骑手,也没有那个必要.那我们能不能把找骑手给你送外卖的环节做成异步的,哪怕有几十秒的延迟,只要我们在一定的时间内给你找到骑手就可以了?送餐就可以了。这是否让您下订单和订购外卖变得超快?支付成功后,您可以直接创建订单,扣款,并通知商家立即为您准备食物。这个过程可能需要数百毫秒。那么后台异步通过调度算法可能需要几十秒才能找到骑手送餐,但这一步不影响我们快速下单。当然,我们并不是说大家熟悉的那些外卖平台的技术架构一定要这样实现,只是用一个生活中常见的例子来给大家说明一下。所以上面的链接也是一样的。如果业务流程支持异步,是不是可以考虑把系统C对系统D的调用提取出来做成异步的,而不是放到链接里,顺序同步调用。这样,实现思路是SystemA→SystemB→SystemC,耗时220ms,直接成功。然后系统C发送消息给MQ中间件,系统D消费消息后,慢慢异步执行这个2s消费的业务流程。这样一来,核心环节的执行性能直接提升了10倍。整个过程如下图所示:流量调峰假设你有一个系统,平时每秒可能有几百个请求。系统部署在8核16G的机器上,正常处理就ok了。几百个请求就很容易被拒绝。但是如下图,在高峰期突然来了每秒几千个请求,瞬间就出现了一个流量高峰。这个时候你的选择是建10台机器来抵挡每秒上千请求的瞬时峰值?那么如果瞬时峰值只有一天半小时,那么直接降到每秒几百个请求。如果在线部署很多机器,那么每台机器每秒可以处理几十个请求。是不是有点浪费机器资源?大部分时候,一台机器每秒几百个请求就够了,但是为了抗住每天的瞬时高峰,部署了10台机器,每天半小时有用。时间是一种资源浪费。但是如果你只部署一台机器,会导致你的系统在瞬间的峰值时不堪重负,因为你是绝对无法抗拒每秒上千请求的峰值的。此时,我们可以使用MQ中间件进行流量削峰。所有机器前面都部署了一层MQ,每个人都可以很轻松的接收到每秒几百个请求的消息。一旦到了瞬时高峰期,MQ中可以积压每秒几千个请求,然后那台机器慢慢处理消费。高峰期结束后,经过一段时间的消费,就会消费掉MQ中积压的数据。这是MQ的典型用法,利用有限的机器资源承载高并发请求。如果业务场景允许异步调峰,在高峰期有部分请求积压在MQ中,高峰期结束后,如果后台系统在一定时间内消费,不再积压,那么这个技术方案非常合适的。引入消息中间件有什么优缺点?如果在系统架构中引入消息中间件,有什么缺点呢?系统可用性的下降,就是你的系统整体的可用性肯定会下降。让我举一个例子。我们拿上一张图来说明。比如在一个核心环节,系统A→系统B→系统C,然后系统C通过MQ异步调用系统D。看起来不错,你用这个MQ异步的方式解决了一个核心环节执行性能差的问题。但是你有没有考虑过另外一个问题,如果你依赖的MQ中间件突然挂了怎么办?这还真不是异想天开,MQ、Redis、MySQL等组件都可能挂掉。一旦你的MQ挂了,就会导致你系统的核心业务流程中断。本来你不引入MQ中间件,其实就是一些系统之间的调用,现在你引入了MQ,导致你多了一个依赖。一旦多了一个依赖,就会降低你的可用性。所以一旦引入MQ中间件,就必须考虑MQ如何部署,如何保证高可用。即使在复杂的高可用场景下,你也得考虑你的系统是否有备份的技术方案,保证系统在MQ挂了的情况下继续运行。系统稳定性的下降还是在上图中。再来看看:不知道大家有没有发现问题。除了MQ中间件可能挂掉的隐患外,这个环节可能还有一些其他的技术问题。比如莫名其妙的,C系统给MQ发了一条消息,但是由于网络故障等问题,消息丢失了。这会导致SystemD收不到该消息。这很惨,因为它会导致系统D无法完成它应该做的任务。这时候整个系统可能会出现业务紊乱、数据丢失、BUG严重、用户体验差等问题。这只是其中之一。万一C系统给MQ发消息,一不小心重复发同一条消息,导致消息重复怎么办。这个时候怎么办?可能会导致系统D一次性插入一条数据。两次,导致数据错误,产生脏数据,同样会导致各种问题。或者系统D突然宕机几个小时,导致无法消费消息。结果大量的消息长期积压在MQ中间件中,这时候怎么办呢?即使D系统恢复了,也需要慢慢消耗数据来处理。所以这是引入MQ中间件的第二个大问题。系统稳定性可能会下降,故障会增加,各种乱七八糟的问题可能会出现。而一旦出现问题,就会导致整个系统出现问题。你需要采取很多技术方案来解决各种MQ带来的技术问题。关于这一点,我们将用一篇专门的文章来谈谈MQ中间件这些问题的解决方案,包括:消息的高可靠传递(0丢包)消息的幂等传递(绝对不重复)百万消息积压的在线故障处理分布式一致性问题引入了消息中间件,同样存在分布式一致性问题。举个例子,假设C系统已经成功的处理了它本地的数据库,然后给MQ发了一条消息,D系统确实消费了。不幸的是,系统D无法操作自己的本地数据库。这个时候怎么办?C系统成功了,D系统失败了,会导致整个系统的数据不一致。所以这个时候就需要使用消息最终一致性可靠的分布式事务方案来保证。关于这一点,可以参考之前的一篇文章:最终一致性分布式事务在实际生产中是如何保证99.99%高可用的?我们详细阐述了在系统间异步调用的场景下,如何使用分布式事务解决方案来保证其数据的一致性。总结最后,我们做一个简单的总结。要在面试中回答好这个问题,首先要熟悉MQ技术的优缺点。清楚自己引入系统解决的是什么问题,又会给自己带来什么问题。另外,在引入MQ之后,对于它可能带来的问题,是否有一些设计方案来保证你的系统的高可用和高可靠,以及数据的一致性。这也应该相应地准备。中华石山:十余年BAT架构经验,一线互联网公司技术总监。带领数百人团队开发过亿级大流量高并发系统。多年工作积累的研究手稿和经验总结,现整理成文,一一传授。微信公众号:石山的建筑笔记(ID:shishan100)。