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

面试官让我聊聊 MQ 的数据丢失问题,没想到水这么深

时间:2023-03-20 20:58:48 科技观察

面试官让我说说MQ的数据丢失问题。没想到水这么深。看过上一篇文章《字节面试官: 让你设计一个MQ每秒要抗几十万并发,怎么做?》的同学应该知道,写入Kafka的数据会写入磁盘。暂且不考虑写入磁盘的具体过程。我们来看下图,它代表了Kafka的核心架构原理。2.Kafka分布式存储架构那么现在的问题是,如果每天产生几十TB的数据,是不是都写在一台机器的磁盘上了?这显然不靠谱!所以,这里不得不考虑数据的分布式存储。其实之前的一篇文章《程序员别死背面试八股文了,这种面试题才是未来主流。。。》也分析过消息中间件的分布式存储和高可用架构,不过这里,我们结合Kafka的具体情况说一下。在Kafka中,有一个核心概念叫做“Topic”。您可以将此主题视为数据收集。例如,如果你现在有一个网站用户行为数据要写入Kafka,你可以创建一个名为“user_access_log_topic”的主题,将所有用户行为数据写入其中。那么,如果要将电商网站的订单数据的增删改查记录写入到Kafka中,可以创建一个名为“order_tb_topic”的topic,其中写入订单表的所有变更记录。那么,举个例子来说说这个用户行为话题。每天几十TB的数据往里面写,你觉得放在一台机器上靠谱吗?显然不靠谱,所以Kafka有一个概念叫Partition,就是把一个topic数据集拆分成多个数据分区。您可以将其视为多个数据片段。每个分区可以存储在不同的机器上。数据。这样一来,不是可以把一个大数据集分布存储在多台机器上吗?看下图,一起来感受一下吧。3、Kafka高可用架构但是这个时候我们又会遇到一个问题,就是如果某台机器宕机了,这台机器上分区管理的数据不会丢失吗?因此,我们必须制作多份副本以备冗余。每个Partition都可以制作一个副本并将其放在另一台机器上。如果一台机器出现故障,只是丢失了一个分区副本。如果一个Partition有多个副本,Kafka会选举其中一个Parititon副本作为Leader,然后其他Partition副本为Follower。只有LeaderPartition对外提供读写操作,FollowerPartition从LeaderPartition同步数据。一旦LeaderPartition宕机,其他FollowerPartition将被选举为新的LeaderPartition,对外提供读写服务。这不是实现了高可用架构吗?看看下面的图片,看看这个过程。4、Kafka写入数据丢失问题下面我们来看一下,Kafka写入数据在什么情况下会丢失?其实也很简单。大家都知道写入的数据是写到一个Partition的Leader上,然后那个Partition的Follower会从Leader上同步数据。但是如果一个数据刚刚写入LeaderPartition,还没来得及同步到Follower,LeaderPartiton所在的机器突然死机了怎么办?看下图:如上图所示,此时有一条数据没有同步到Partition0的Follower上,然后Partition0的Leader所在的机器就挂了。这时候Partition0的Follower会被选举为新的Leader对外提供服务,那么用户就无法读取刚刚写入的数据了?因为Partition0的Follower还没有同步到最新的一条数据。这时候就会造成数据丢失的问题。5、Kafka的ISR机制是什么?现在让我们把这个问题搁置一边,不谈如何解决它。我们再回顾一下Kafka的一个核心机制,就是ISR机制。简单来说,这个机制就是自动为每个Partition维护一个ISR列表。这个列表中必须有一个Leader,然后它还会包含与Leader保持同步的Follower。也就是说,Leader的一个Follower只要和他保持数据同步,就会存在于ISR列表中。但是如果Follower因为自身的一些问题不能及时从Leader同步数据,那么这个Follower就会被认为“不同步”,被踢出ISR列表。所以大家首先要明白这个ISR是什么。说白了就是Kafka自动维护和监控哪些Follower及时跟上Leader的数据同步。6、如何保证数据不丢失?所以想要保证写入Kafka的数据不丢失,需要要求几点:每个Partition在ISR列表中至少要有一个Follower,并且跟上Leader的数据同步。每次写入数据,必须至少向PartitionLeader写入成功,ISR中至少有一个Follower也在写入成功,才算写入成功。如果不满足以上两个条件,写入会一直失败,导致生产系统停止尝试重试,直到满足以上两个条件,才可以认为写入成功,根据以上思路保证写入Kafka的数据不会丢失!下面我们来分析一下上面的需求。首先,ISR列表中必须至少有一个Follower。那是必要的。如果Leader没有Follower,或者Follower不能及时同步Leader的数据,那么这件事情肯定是办不下去的。第二,每次写入数据时,要求不仅leader写入成功,而且ISR中至少有一个follower也写入成功。看下面的图片。这个要求是为了保证每次写入数据时,leader和follower都必须写入成功才算写入成功。保证一条数据一定有两个以上的副本。这时候如果leader宕机了,可以切换到follower。那么follower有刚刚写入的数据,此时数据不会丢失。如上图所示,如果leader现在没有follower,或者只是写给leader,leader会立即关闭,然后才能同步给follower。这种情况下,写入会失败,然后你会让producer不断重试,直到kafka恢复正常,满足以上条件再继续写入。这样写入kafka的数据就不会丢失。7.总结最后总结一下,其实Kafka中数据丢失的问题涉及方方面面。比如生产端的缓存问题,包括消费者端的问题,以及Kafka自身内部的底层算法和机制,也有可能造成数据丢失。但是写数据通常会遇到一个比较大的问题,就是leader切换的时候可能会出现数据丢失的情况。所以这篇文章只是说说生产环境下这个问题的解决方法。