1.我之前写过一篇文章《项目里接入了MQ消息中间件以后,我摸鱼的时间更长了~》。我们通过一个简单易懂的电子商务场景来介绍和讲解一个消息中间件的使用场景。同时,基于RabbitMQ的HelloWorld代码,我们还举例说明了订单服务和存储服务是如何基于MQ中间件收发消息的。2.业务场景回顾本文,深入探讨一下MQ中间件使用中的一些基本技术问题。首先回顾一下上篇文章做的一个架构图,看看订单服务和消息服务是如何基于MQ收发消息的。让我们稍微完善一下这张图。简单来说就是多个订单服务实例向队列推送消息,多个存储服务各自消费一部分消息。如下图所示:3.意外宕机,问题凸显如果你对MQ技术的在线使用到此为止,那么你基本上可以和offer说拜拜了。..因为如果是我,作为一个面试官,我不能继续问问题。如果你对MQ的使用和理解的深度仅此而已,那基本上就是刚刚入门MQ技术的水平。如果面试官想继续问,可以问下面的问题:然后告诉我,如果存储服务是消费服务,你刚收到一个订单消息,但是在消息处理之前,也就是存储调度订单尚未完成。出货了,仓储服务突然宕机了,这时候会发生什么?所以大家还是需要对这项技术有一点深入的了解,不然问几个问题就完了。我们先来看看下图,感受一下车祸现场。RabbitMQ中间件的一个默认行为是,只要存储服务收到订单消息,RabbitMQ就会立即将订单消息标记为已删除。这种行为称为自动ack,即消息投递后,会自动确认。消息已处理。但是那么如果此时仓储服务收到了订单消息,但是还没有来得及完成货物的调度和发货到仓库系统,结果就会直接down。这时候很明显订单消息丢失了,因为RabbitMQ已经不存在了。..这会导致什么样的尴尬经历?即某用户支付了8999元,下单购买了一台iphone8。结果等了好几天,网站上也没有看到他的iphone8送货上门。工作了半天,原因是他的iphone8订单在仓储服务,还没来得及派送就宕机了,导致订单消息一直丢失,一直没有通知仓库系统向用户交付货物。.这个问题很尴尬吗?因此,技术问题会严重影响企业的核心业务流程!小伙伴们记得上一讲我们的仓储服务消费消息的代码中有一行关键代码:这行代码是针对channel.basicConsume()方法的,传入的第二个参数:true,也就是实际上是一个关键参数。这个true代表一个核心意思。这意味着只要RabbitMQ向存储服务投递消息,它就会立即将消息标记为已删除。但是,在这种默认配置下,如果仓库服务收到一条订单消息,未能完成需要几十秒的仓库调度和发货业务逻辑,突然崩溃,那么订单消息将永久丢失!找了半天,原来问题的症结就在这里!你明白为什么我在上一篇文章的最后说这段代码到目前为止还有很多问题吗?所以这个时候,如果我们不想因为存储服务突然宕机而丢失一条订单消息,就需要修改存储服务消费消息的代码。首先,我们需要将参数从true改为false,如下代码所示:只要改为false,RabbitMQ就不会盲目投递消息到存储服务,并立即删除消息.说白了就是关闭autoAck行为,不要假设消息处理成功。接下来,我们需要修改处理订单消息的代码,如下代码所示。这段代码,说白了,就是在调度订单发货后,在finally代码块中手动执行ack操作,说我已经完成了需要几十秒的业务逻辑处理,现在可以手动ack了通知RabbitMQ消息已被处理。至此,整个架构运行流程大致如下图所示。架构流程改为上述后,意味着仓库服务只有在仓库调度和发货的代码业务逻辑完成后,才会在代码中手动向RabbitMQ发送ack消息,以确保仓库系统收到通知。此时RabbitMQ收到ack消息后会将对应的订单消息标记为已删除。如果仓储服务收到了订单消息,但是仓储调度和发货的业务逻辑还没有及时完成,那么这条订单消息的ack操作永远不会执行,那么RabbitMQ就不会收到这条订单消息ack通知。一旦RabbitMQ发现代表消费者的一个存储服务实例突然宕机,存储服务收到的一些订单消息还没有来得及处理,它们就不会向自己发送这些消息的ack通知。此时,RabbitMQ会自动将订单消息重新发送给其他正在运行的仓储服务实例,让其他仓储服务实例处理订单消息。这样可以保证这条订单消息不会因为某个存储服务实例宕机而丢失。它将确保某个存储服务实例在删除订单消息之前必须完成对该订单消息的调度和交付处理。4、总结tips最后再来一张图,大家可以直观感受一下:好了同学们,这篇文章是不是深入一点,让大家明白一些使用MQ技术时应该考虑的问题?其实无论是RocketMQ、Kafka还是RabbitMQ,都有类似的autoAck或者manualack机制。在在线生产环境中运行时,必须考虑消费者服务可能出现的宕机。如果消费者服务在处理消息之前就关闭了,会导致部分消息丢失,从而影响核心业务流程的运行。所以,大家在线上使用MQ的时候,一定要充分考虑这些潜在的问题,同时结合具体MQ提供的一些API和参数进行合理的设置,保证消息不会随意丢失。
