消息中间件消费到的消息处理失败怎么办?

阅读本文大概需要 6.2 分钟。

作者:爱钓鱼的桌子哥

1、日趋流行的面试问法

现在网上很多面试题,主要是针对技术本身的提问,比如:你聊聊对Dubbo的理解?你说说分布式事务是什么?

这些问题就好比中学考试的送分题,比如默写古诗,你只要准备了,下点功夫,都没啥问题。

所以这里对技术本身的提问,其实就相当于送分题,主要是做一个基本的区分。你能回答出来,说明你至少平时还注意积累知识,不是一个混日子的工程师。

但是现在出去面试,尤其是一些大厂的面试越来越难了,从以前普通的技术知识本身,现在到了会考察你很多生产环境中的一些特殊状况。

也就是说从以前的知识积累和背诵,到现在开始考察你的具体实践和经验积累。

比如现在可能很多面试官开始这么问:你们项目里用Dubbo时,有没有遇到什么技术问题?你们Dubbo服务的超时一般怎么设置的?服务之间调用一般会遇到超时吗?如果超时了会怎么样?

类似这样的问题,都是在考察你对一个技术的实践经验,而这目前越来越成为了面试的重点。

所以本文将通过一道面试中的经典高频问题:消息中间件消费到的消息处理失败了怎么办?

借助这道经典题目,来阐述一下这个问题。我们应该从哪些角度思考,才能做出满分回答。

2、消息中间件在生产系统中的使用

这是一个非常典型的生产环境的问题,很多公司都会在生产系统里使用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出错而已,不影响别人。

3、经典生产案例:早教盒子APP的发货

接下来用一个经典的生产案例给大家说说MQ在生产的使用。

现在很多早教类的APP,都会提供早教盒子,什么意思呢?

早教APP提供的核心服务就是三块:

1、APP里的早教视频课程

2、线上微信群的助教答疑指导

3、线下送你早教盒子,里面有很多上课道具

这样一个妈妈陪伴孩子上早教的过程可能是这样的:

1、首先在APP里看早教视频课程,孩子看着很感兴趣。

2、接着妈妈从早教盒子里取出来道具,陪孩子把视频里的游戏和任务都做一遍,让孩子加深印象

3、最后每天妈妈会打卡,有助教会来给妈妈进行答疑。

所以说,假设现在我们要在一个早教APP里购买一个早教课程,他的流程大致如下:

1、选择购买早教课程

2、直接支付

3、创建订单

4、给用户增加课程权限

5、通知仓库准备发早教盒子

6、通知物流公司去仓库取早教盒子进行配送。

我们来分析一下每个环节。首先你要是购买一个早教课程,那么点击“购买”的按钮之后,一般直接会跳入一个支付界面。

这个时候,你就可以直接选择支付了。此时后台系统一定会通过支付系统跟第三方支付系统进行通信,比如说支付宝、微信之类的,然后等待支付完成。

一旦支付完成,就会在自己内部系统干两个事:

第一,给这个用户id创建一个订单;

第二,给这个用户id增加看某个早教视频课程的权限。

此时用户其实在“我的订单”界面就可以看到自己的订单了,而且在“我的课程”界面,就可以开始看早教课程的视频了。

如果对上面过程不太理解的,再看看下面的图,应该就清楚了:

但是现在问题主要在后面两个步骤,现在你的订单系统作为核心入口,他要通知仓库系统去扣减一个早教盒子的库存。

同时,还得准备好早教盒子的发货(比如说提前打包装箱,准备一些给快递公司使用的发货单之类的,需要帖子箱子上)。

然后通知第三方物流公司的系统,可以去自己的仓库取早教盒子发货了。

这两个步骤需要涉及到对仓库系统以及第三方物流公司系统的调用,那么是采用订单系统直接同步调用那两个系统的方式吗?

恐怕不妥,因为这里最大的问题就是性能问题和可用性问题。

举个例子,假如现在仓库系统部署在其他地方,因为网络问题导致性能很差,访问速度很慢,那么是不是可能会导致用户支付之后,等待了几分钟都看不到整个流程的完成?

或者要是说第三方物流公司的系统现在要是故障了,暂时无法访问,那么会不会导致用户支付了之后,一直没有给用户发货早教盒子?

所以说,在这里就应该引入MQ,订单系统在完成订单的创建以及课程的分配之后,就可以发送一个消息到MQ,然后有一个专门的仓储系统负责消费这个消息,接着尝试去调用独立仓库系统通知发货,以及通知第三方物流系统去配送。

整个过程,如下图所示:

这么做有什么好处呢?

好处是显而易见的,假如现在独立仓库系统和第三方物流系统的访问性能突然变得很差,大不了就是仓储系统在后面慢慢的跟人家通信等着人家处理完毕好了,对订单系统是没影响的。

对于订单系统而言,创建订单和分配课程都是速度很快的,然后发送个消息到MQ速度也很快。

这样一来,用户看到的就是一两秒的时间支付就成功了,然后可以查到订单,看到自己的课程,然后订单的物流显示的是“待配送”的状态。

那么如果独立仓库系统或者第三方物流系统故障了,导致仓储系统消费到一条订单消息之后,尝试进行发货失败,也就是对这条消费到的消息处理失败。这种情况,怎么处理?

这就是本文最核心的地方了!!!

4、死信队列的使用:处理失败的消息

一般生产环境中,如果你有丰富的架构设计经验,都会在使用MQ的时候设计两个队列:一个是核心业务队列,一个是死信队列。

核心业务队列,就是比如上面专门用来让订单系统发送订单消息的,然后另外一个死信队列就是用来处理异常情况的。

之所以我们这篇文章抛出一个面试题,结果先长篇大论说一个生产实践案例和业务场景,就是因为面试被问到这个问题时,必须要结合你自己的业务实践经验来说。

你需要先给面试官说有血有肉的业务系统场景,然后再结合这个场景回答他的问题,因为面试官想听的就是你真实的实践经验。

比如说要是第三方物流系统故障了,此时无法请求,那么仓储系统每次消费到一条订单消息,尝试通知发货和配送,都会遇到对方的接口报错。

此时仓储系统就可以把这条消息拒绝访问,或者标志位处理失败!注意,这个步骤很重要。

一旦标志这条消息处理失败了之后,MQ就会把这条消息转入提前设置好的一个死信队列中。

然后你会看到的就是,在第三方物流系统故障期间,所有订单消息全部处理失败,全部会转入死信队列。

然后你的仓储系统得专门有一个后台线程,监控第三方物流系统是否正常,能否请求的,不停的监视。

一旦发现对方恢复正常,这个后台线程就从死信队列消费出来处理失败的订单,重新执行发货和配送的通知逻辑。

死信队列的使用,其实就是MQ在生产实践中非常重要的一环,也就是架构设计必须要考虑的。

整个过程,如下图所示:

5、总结

最后再给各位朋友强调一下,如果面试被问到生产实践类的问题,一定记住:结合有血有肉的业务系统和场景来阐述你的实践经验,以及在业务场景下,应该如何设计技术方案。

这样你的回答,才能匹配上面试官内心深处最希望听到的满分答案!

·END·

程序员的成长之路

路虽远,行则必至

本文原发于 同名微信公众号「程序员的成长之路」,回复「1024」你懂得,给个赞呗。

回复 [ 520 ] 领取程序员最佳学习方式

回复 [ 256 ] 查看 Java 程序员成长规划

往期精彩回顾

记住:永远不要在 MySQL 中使用 UTF-8

IDEA 调试图文教程,让 bug 无处藏身!

SSM 实现支付宝支付功能(图文详解+完整代码)

Java中的锁原理、锁优化、CAS、AQS详解!

架构师成长之路之限流漫谈

为什么程序员应该有一台 Mac 个人电脑

通过一个简书评论,挖掘一个商业模式

原文地址:https://www.cnblogs.com/gdjk/p/10898360.html

时间: 2024-10-12 05:32:57

消息中间件消费到的消息处理失败怎么办?的相关文章

消息中间件消费到的消息处理失败怎么办?热门面试题的满分答案!

1.日趋流行的面试问法 现在网上很多面试题,主要是针对技术本身的提问,比如:你聊聊对Dubbo的理解?你说说分布式事务是什么? 这些问题就好比中学考试的送分题,比如默写古诗,你只要准备了,下点功夫,都没啥问题. 所以这里对技术本身的提问,其实就相当于送分题,主要是做一个基本的区分.你能回答出来,说明你至少平时还注意积累知识,不是一个混日子的工程师. 但是现在出去面试,尤其是一些大厂的面试越来越难了,从以前普通的技术知识本身,现在到了会考察你很多生产环境中的一些特殊状况. 也就是说从以前的知识积累

分布式最终一致性事务

一.强一致性事务的瓶颈 在<分布式强一致性事务>一文中介绍了分布式事务的常用协议2PC二阶段提交,虽然2PC能在很大程度上实现分布式事务中各节点的ACID,但也存在同步阻塞问题,协调者单点故障,协调者因网络原因导致的通知不周或收不全参与者回复导致的异常等问题. 同时,即使能稳定的使用二阶段提交实现分布式事务,但是2PC通信过程中产生的耗时是巨大的,类似淘宝网,下完一个订单后可能需要与计费中心,订单中心,入库,出库等很多子系统打交道,此过程中带来的开销是不能接受的,等到所有流程通知响应完再返回告

Rabbitmq消费失败死信队列

Rabbitmq 重消费处理 一 处理流程图: 业务交换机:正常接收发送者,发送过来的消息,交换机类型topic AE交换机: 当业务交换机无法根据指定的routingkey去路由到队列的时候,会全部发送到AE交换机.发送到此队列的消息属于,业务垃圾消息,或者攻击消息类型,交换机类型fanout 死信交换机:用于处理消费者,消费失败回退的消息,根据死信交换机的routingkey发送到死信队列,交换机类型 topic EXAMPLE: 业务routingkey: hello/task_queue

Spring Cloud Stream消费失败后的处理策略(三):使用DLQ队列(RabbitMQ)

应用场景 前两天我们已经介绍了两种Spring Cloud Stream对消息失败的处理策略: 自动重试:对于一些因环境原因(如:网络抖动等不稳定因素)引发的问题可以起到比较好的作用,提高消息处理的成功率. 自定义错误处理逻辑:如果业务上,消息处理失败之后有明确的降级逻辑可以弥补的,可以采用这种方式,但是2.0.x版本有Bug,2.1.x版本修复. 那么如果代码本身存在逻辑错误,无论重试多少次都不可能成功,也没有具体的降级业务逻辑,之前在深入思考中讨论过,可以通过日志,或者降级逻辑记录的方式把错

消息中间件(一)JMS与ActiveMQ

JMS基础参见:http://blog.csdn.net/zhangxs_3/article/category/625599 实践中存在的问题(引自<大型网站系统与Java中间件实践>第六章): 一.如何解决消息发送一致性 1.消息发送一致性定义 消息发送一致性是指产生消息的业务动作与发送消息的一致,也就是说,如果业务操作成功了,那么由这个操作产生的消息一定要发送出去,否则就丢失消息了.另一方面,如果业务操作没有发生或者是失败了,就不应该把消息发出去. 2.消息一致性很难保证吗 解决方式一:

互联网面试必杀:如何保证消息中间件全链路数据100%不丢失

背景引入 这篇文章,我们来聊聊在线上生产环境使用消息中间件技术的时候,从前到后的全链路到底如何保证数据不能丢失. 这个问题,在互联网公司面试的时候高频出现,而且也是非常现实的生产环境问题. 如果你的简历中写了自己熟悉MQ技术(RabbitMQ.RocketMQ.Kafka),而且在项目里有使用的经验,那么非常实际的一个生产环境问题就是:投递消息到MQ,然后从MQ消费消息来处理的这个过程,数据到底会不会丢失. 面试官此时会问:如果数据会丢失的话,你们项目生产部署的时候,是通过什么手段保证基于MQ传

消息中间件面试题31道RabbitMQ+ActiveMQ+Kafka

前言 文章开始前,我们先了解一下什么是消息中间件? 什么是中间件? 非底层操作系统软件,非业务应用软件,不是直接给最终用户使用的,不能直接给客户带来价值的软件统称为中间件. 什么是消息中间件? 是关注于数据的发送和接收,利用高效可靠的异步消息传递机制集成分布式系统 图示: 消息中间件RabbitMQ+ActiveMQ+Kafka的对比 接下来就是消息中间件面试题RabbitMQ+ActiveMQ+Kafka RabbitMQ消息中间件系列 1:RabbitMQ 中的 broker 是指什么?cl

消息中间件搬迁

消息队列 原理 消息存储 Pull方式 Push方式 高可用 异常重试 生产者端的消息失败 消费者端的消失失败 顺序性 对比 消息队列 作用:异步,解藕,峰值处理,可恢复,顺序,扩展性 RocketMq源码部分主要可以分为 rocketmq-broker,rocketmq-client,rocketmq-common,rocketmq-filterSrv,rocketmq-namesrv和rocketmq-remoting等模块, 通信框架就封装在rocketmq-remoting模块中 原理

Spring Boot 实现 RabbitMQ 延迟消费和延迟重试队列

本文主要摘录自:详细介绍Spring Boot + RabbitMQ实现延迟队列 并增加了自己的一些理解,记录下来,以便日后查阅. 项目源码: spring-boot-rabbitmq-delay-queue 实现 stream-rabbitmq-delay-queue 实现 背景 何为延迟队列? 顾名思义,延迟队列就是进入该队列的消息会被延迟消费的队列.而一般的队列,消息一旦入队了之后就会被消费者马上消费. 延迟队列能做什么?延迟队列多用于需要延迟工作的场景.最常见的是以下两种场景: 延迟消费