做者:爱钓鱼的桌子哥程序员
一、日趋流行的面试问法面试
如今网上不少面试题,主要是针对技术自己的提问,好比:你聊聊对Dubbo的理解?你说说分布式事务是什么?数据库
这些问题就比如中学考试的送分题,好比默写古诗,你只要准备了,下点功夫,都没啥问题。微信
因此这里对技术自己的提问,其实就至关于送分题,主要是作一个基本的区分。你能回答出来,说明你至少平时还注意积累知识,不是一个混日子的工程师。网络
可是如今出去面试,尤为是一些大厂的面试愈来愈难了,从之前普通的技术知识自己,如今到了会考察你不少生产环境中的一些特殊情况。架构
也就是说从之前的知识积累和背诵,到如今开始考察你的具体实践和经验积累。异步
好比如今可能不少面试官开始这么问:大家项目里用Dubbo时,有没有遇到什么技术问题?大家Dubbo服务的超时通常怎么设置的?服务之间调用通常会遇到超时吗?若是超时了会怎么样?分布式
相似这样的问题,都是在考察你对一个技术的实践经验,而这目前愈来愈成为了面试的重点。性能
因此本文将经过一道面试中的经典高频问题:消息中间件消费到的消息处理失败了怎么办?学习
借助这道经典题目,来阐述一下这个问题。咱们应该从哪些角度思考,才能作出满分回答。
二、消息中间件在生产系统中的使用
这是一个很是典型的生产环境的问题,不少公司都会在生产系统里使用MQ,即消息队列,或者消息中间件。
也就是说,一个系统跟另一个系统之间进行通讯的时候,假如系统A但愿发送一个消息给系统B,让他去处理。
可是系统A不关注系统B到底怎么处理或者有没有处理好,因此系统A把消息发送给MQ,而后就无论这条消息的“死活”了,接着系统B从MQ里消费出来处理便可。
至于怎么处理,是否处理完毕,何时处理,都是系统B的事儿,与系统A无关。
上述过程,能够经过下图看的很清晰:
这样的一种通讯方式,就是所谓的“异步”通讯方式
对于系统A来讲,只要把消息发给MQ,而后系统B就会异步的去进行处理了,系统A不须要“同步”的等待系统B处理完。
这样的好处是什么呢?
两个字:解耦
系统A要跟系统B通讯,可是他不须要关注系统B如何处理的一些细节。咱们来举几个例子说明:
好比,A不须要关注B何时处理完,这样假如系统B处理一个消息要耗费10分钟也不关系统A的事儿。
不然,系统A直接调用系统B的接口,系统B一会儿处理了10分钟怎么办?难不成系统A也阻塞等待10分钟?
再好比,系统A不须要关注系统B处理成功与否,即便系统B处理失败了,也是系统B本身去考虑这个场景和从新尝试处理。
不然若是系统调用系统B的接口,万一处理失败了报错了,系统A受到一个调用异常该怎么处理?
还有,系统A不须要关注系统B是否存活。万一要是系统B挂掉了,系统A经过MQ来通讯也不须要管系统B的“死活”,系统B本身恢复了以后就能够从MQ消费消息再次处理便可。
不然系统A直接调用系统B的接口,万一系统B挂了,难道系统A还要把消息暂存到数据库?等待系统B恢复了再给他发过去吗?
这就是经过MQ进行异步通讯,让两个系统解耦以后的好处,能够大幅度提高整个大系统的容错性,增长系统的弹性,而不是到处耦合,一个系统出错连带致使其余系统所有出错。
解耦以后,即便出错也只是大系统中的一个系统B出错而已,不影响别人。
三、经典生产案例:早教盒子APP的发货
接下来用一个经典的生产案例给你们说说MQ在生产的使用。
如今不少早教类的APP,都会提供早教盒子,什么意思呢?
早教APP提供的核心服务就是三块:
一、APP里的早教视频课程
二、线上微信群的助教答疑指导
三、线下送你早教盒子,里面有不少上课道具
这样一个妈妈陪伴孩子上早教的过程多是这样的:
一、首先在APP里看早教视频课程,孩子看着很感兴趣。
二、接着妈妈从早教盒子里取出来道具,陪孩子把视频里的游戏和任务都作一遍,让孩子加深印象
三、最后天天妈妈会打卡,有助教会来给妈妈进行答疑。
因此说,假设如今咱们要在一个早教APP里购买一个早教课程,他的流程大体以下:
一、选择购买早教课程
二、直接支付
三、建立订单
四、给用户增长课程权限
五、通知仓库准备发早教盒子
六、通知物流公司去仓库取早教盒子进行配送。
咱们来分析一下每一个环节。首先你要是购买一个早教课程,那么点击“购买”的按钮以后,通常直接会跳入一个支付界面。
这个时候,你就能够直接选择支付了。此时后台系统必定会经过支付系统跟第三方支付系统进行通讯,好比说支付宝、微信之类的,而后等待支付完成。
一旦支付完成,就会在本身内部系统干两个事:
第一,给这个用户id建立一个订单;
第二,给这个用户id增长看某个早教视频课程的权限。
此时用户其实在“个人订单”界面就能够看到本身的订单了,并且在“个人课程”界面,就能够开始看早教课程的视频了。
若是对上面过程不太理解的,再看看下面的图,应该就清楚了:
可是如今问题主要在后面两个步骤,如今你的订单系统做为核心入口,他要通知仓库系统去扣减一个早教盒子的库存。
同时,还得准备好早教盒子的发货(好比说提早打包装箱,准备一些给快递公司使用的发货单之类的,须要帖子箱子上)。
而后通知第三方物流公司的系统,能够去本身的仓库取早教盒子发货了。
这两个步骤须要涉及到对仓库系统以及第三方物流公司系统的调用,那么是采用订单系统直接同步调用那两个系统的方式吗?
恐怕不妥,由于这里最大的问题就是性能问题和可用性问题。
举个例子,假如如今仓库系统部署在其余地方,由于网络问题致使性能不好,访问速度很慢,那么是否是可能会致使用户支付以后,等待了几分钟都看不到整个流程的完成?
或者要是说第三方物流公司的系统如今要是故障了,暂时没法访问,那么会不会致使用户支付了以后,一直没有给用户发货早教盒子?
因此说,在这里就应该引入MQ,订单系统在完成订单的建立以及课程的分配以后,就能够发送一个消息到MQ,而后有一个专门的仓储系统负责消费这个消息,接着尝试去调用独立仓库系统通知发货,以及通知第三方物流系统去配送。
整个过程,以下图所示:
这么作有什么好处呢?
好处是显而易见的,假如如今独立仓库系统和第三方物流系统的访问性能忽然变得不好,大不了就是仓储系统在后面慢慢的跟人家通讯等着人家处理完毕好了,对订单系统是没影响的。
对于订单系统而言,建立订单和分配课程都是速度很快的,而后发送个消息到MQ速度也很快。
这样一来,用户看到的就是一两秒的时间支付就成功了,而后能够查到订单,看到本身的课程,而后订单的物流显示的是“待配送”的状态。
那么若是独立仓库系统或者第三方物流系统故障了,致使仓储系统消费到一条订单消息以后,尝试进行发货失败,也就是对这条消费到的消息处理失败。这种状况,怎么处理?
这就是本文最核心的地方了!!!
四、死信队列的使用:处理失败的消息
通常生产环境中,若是你有丰富的架构设计经验,都会在使用MQ的时候设计两个队列:一个是核心业务队列,一个是死信队列。
核心业务队列,就是好比上面专门用来让订单系统发送订单消息的,而后另一个死信队列就是用来处理异常状况的。
之因此咱们这篇文章抛出一个面试题,结果先长篇大论说一个生产实践案例和业务场景,就是由于面试被问到这个问题时,必需要结合你本身的业务实践经验来讲。
你须要先给面试官说有血有肉的业务系统场景,而后再结合这个场景回答他的问题,由于面试官想听的就是你真实的实践经验。
好比说要是第三方物流系统故障了,此时没法请求,那么仓储系统每次消费到一条订单消息,尝试通知发货和配送,都会遇到对方的接口报错。
此时仓储系统就能够把这条消息拒绝访问,或者标志位处理失败!注意,这个步骤很重要。
一旦标志这条消息处理失败了以后,MQ就会把这条消息转入提早设置好的一个死信队列中。
而后你会看到的就是,在第三方物流系统故障期间,全部订单消息所有处理失败,所有会转入死信队列。
而后你的仓储系统得专门有一个后台线程,监控第三方物流系统是否正常,可否请求的,不停的监视。
一旦发现对方恢复正常,这个后台线程就从死信队列消费出来处理失败的订单,从新执行发货和配送的通知逻辑。
死信队列的使用,其实就是MQ在生产实践中很是重要的一环,也就是架构设计必需要考虑的。
整个过程,以下图所示:
五、总结
最后再给各位朋友强调一下,若是面试被问到生产实践类的问题,必定记住:结合有血有肉的业务系统和场景来阐述你的实践经验,以及在业务场景下,应该如何设计技术方案。
这样你的回答,才能匹配上面试官心里深处最但愿听到的满分答案!
·END·
程序员的成长之路
路虽远,行则必至
本文原发于 同名微信公众号「程序员的成长之路」,回复「1024」你懂得,给个赞呗。
回复 [ 520 ] 领取程序员最佳学习方式
回复 [ 256 ] 查看 Java 程序员成长规划
往期精彩回顾