1.背景如何保证数据在最后的全链路不丢失。这个问题在互联网公司面试的时候经常出现,也是一个很现实的生产环境问题。如果你在简历中写到熟悉MQ技术(RabbitMQ、RocketMQ、Kafka),并且有在项目中使用过的经验,那么一个很实际的生产环境问题就是:向MQ投递消息,然后消费MQ的消息用于processing在这个过程中,数据不会丢失。面试官这时候会问:如果数据会丢失,在你的项目生产部署过程中,通过什么方式保证基于MQ传输的数据100%不丢失?请与您在线使用的消息中间件分享您的技术解决方案。这其实是一个区分面试者技术水平的问题。事实上,有相当一部分普通工程师,甚至是曾在一些中小互联网公司工作过的工程师,只是简单地使用公司部署的MQ集群。也许代码层面基本上就是发送和消费消息。考虑太多的技术解决方案。但实际上,在使用MQ、缓存、分库分表、NoSQL、中间件等各种技术时,会出现一堆与相应技术相关的生产环境问题。针对这些问题,需要有一套相应的技术方案来保证系统的健壮性、稳定性和高可用性。所以其实大中型互联网公司的面试官在面试应聘者的时候,如果考察MQ相关技术的使用经验和掌握情况,十有八九会抛出使用MQ肯定会涉及到的数据丢失问题。因为这道题,很好的区分了考生的技术水平。那么本文就来谈谈在RabbitMQ等消息中间件的背景下,在向MQ投递消息以及从MQ消费消息的过程中,数据丢失的风险和可能性。那我们就一起来看看,如何结合MQ自身提供的一些技术特性来保证数据不丢失呢?2.回顾之前的情况我们从两个角度讨论了如何防止数据丢失:消费者突然宕机可能导致的数据丢失和集群突然崩溃可能导致的数据丢失。总之,希望对MQ不熟悉的同学先熟悉一下前面的系列文章,再来系统的学习一下MQ数据是如何做到100%不丢失的。3.现有的技术方案在之前的文章中已经讨论过了。目前我们已经初步知道,首先会造成数据丢失的地方是消费者收到消息后,还没来得及处理,就直接关机了。.这时RabbitMQ的自动ack机制会通知MQ集群消息已经处理完毕,MQ集群会删除消息。那么这个消息不是丢失了吗?没有消费者会处理这条消息。所以我们之前详细讨论过,通过调整consumer服务中的手动ack机制,保证消息必须已经处理成功,才向MQ集群发送ack通知。否则,在发送ack之前,消费者服务已关闭。这时候MQ集群会自动感知,然后重新发送消息给其他的消费服务实例。当时除了数据丢失问题,还有一个问题,就是如果MQ集群本身突然宕机,会不会造成数据丢失?默认情况下,是的,因为队列和消息都不是以持久化的方式传递的,所以重启MQ集群会导致一些数据丢失。所以在这篇《如果你公司里的MQ集群崩溃了,你能确保数据绝对不丢失吗?》这篇文章中,我们分析了如何以持久化的方式创建队列,同时使用持久化的方式将消息投递到MQ集群,让MQ集群将消息持久化到磁盘。这时候如果消息还没有投递到消费者服务,然后MQ集群突然宕机,数据不会丢失,因为MQ集群重启后,会自动从磁盘加载未投递的消息文件,然后继续交付服务消费者。同样,方案沉淀的系统架构图如下:4、100%数据不丢失?大家想一想,到目前为止,我们的架构能保证数据不丢失吗?事实上,目前的架构仍然存在数据可能丢失的问题。即上述订单服务作为生产者将消息投递到MQ集群后,暂时还驻留在MQ的内存中,还没来得及持久化到磁盘,还没有来得及作为消费者将其交付给存储服务。如果此时MQ集群本身突然宕机怎么办?尴尬了,驻留在内存中的数据肯定会丢失,我们看下图。5、按需制定技术方案现在,我们需要考虑的技术方案是:订单服务如何保证消息必须持久化到磁盘?事实上,订单服务作为生产者向MQ集群投递消息的过程很容易丢数据。比如网络出了问题,根本没有传输数据,或者上面提到的消息刚被MQ接收到,还停留在内存中,没有落地磁盘。这时候MQ集群宕机就会丢失数据。.所以首先我们要考虑作为生产者的订单服务如何利用RabbitMQ提供的相关功能来实现一个技术方案。该技术方案需要保证:只要订单服务发送的消息确认成功,此时MQ集群一定已经将消息持久化到磁盘。我们必须要达到这样的效果,才能保证下发到MQ集群的数据不会丢失。六、需要研究的技术细节这里需要研究的技术细节是:仓库服务手册ack保证数据不丢失的实现原理。之前,笔者收到了很多同学的提问:仓储服务如何做到基于人工ack不丢失数据?RabbitMQ的底层实现有哪些细节和原理?为什么仓储服务不发送ack就宕机了,而RabbitMQ可以自动感知到宕机,然后自动重发消息给其他仓储服务实例呢?这些东西背后的实现原理和底层细节是什么?大家别急。接下来,我们将通过系列文章仔细探究这背后的原理。
