1。之前写大厂面试的时候,一旦简历上写了Kafka,几乎难免会被问到一个问题:说说acks参数对消息持久化的影响?acks参数是kafka使用中非常核心和关键的一个参数,决定了很多东西。因此,无论是面试还是实际项目使用,这篇文章对Kafka的acks参数的分析以及背后的原理都值得一看。2、如何保证宕机时数据不丢失?要想理解这个acks参数的含义,首先要理解Kafka的高可用架构原理。比如下图,对于每个Topic,我们可以设置它包含若干个Partition,每个Partition负责存储Topic的一部分数据。然后,在Kafka的Broker集群中,每台机器上都存储了一些Partition,其中也存储了一部分Topic数据,这样Topic数据就分布存储在一个Broker集群上。但是有个问题,万一一个KafkaBroker宕机了,这时候上面存储的数据不会丢失吗?没错,这是一个比较大的问题。分布式系统中的数据丢失问题是他首先要解决的。任何一台机器一旦宕机,都会导致数据丢失。3、多副本冗余的高可用机制那么如果分析任何分布式系统的原理,比如zookeeper、kafka、rediscluster、elasticsearch、hdfs等,其实它都有自己的一套内部多-copy冗余机制,多副本冗余是几乎任何优秀的分布式系统都应该具备的功能。在Kafka集群中,每个Partition都有多个副本,其中一个副本称为leader,其他副本称为follower,如下图所示。如上图所示,假设一个Topic被拆分成3个Partition,分别是Partition0、Partiton1、Partition2。此时每个Partition都有2份。比如Partition0有一份Leader和一份Follower。Leader和Follower的两份副本分布在不同的机器上。这样的多副本冗余机制可以保证任何一台机器挂了,数据不会完全丢失,因为至少其他机器上还有副本。4、如何在多副本之间同步数据?那我们来看看多副本之间是如何同步数据的?事实上,对于任何一个Partition,只有Leader提供读写服务。也就是说,如果客户端向一个Partition写入数据,通常是写入到该Partition的Leader副本中。那么Leader副本接收到数据后,Follower副本会不断的向他发送请求去尝试拉取最新的数据,拉取到自己的本地,写入磁盘。如下图所示:5.ISR具体指的是什么?了解了Partiton的多副本同步数据机制后,可以看看什么是ISR。ISR的全称是“In-SyncReplicas”,即保持同步的副本。这意味着追随者总是与领导者保持同步。大家可以想一想,如果一个follower所在的Broker因为JVMFullGC等问题卡住了,不能及时从leader拉取同步数据,follower的数据会不会比leader落后很多?所以这个时候,就意味着Follower不再和Leader建立同步关系了。但是只要Follower一直及时从Leader同步数据,就可以保证他们是同步关系。所以每个Partition都有一个ISR,这个ISR里面肯定有一个Leader,因为Leader确信数据是最新的,那么那些和Leader保持同步的Follower也会在ISR里面。6.acks参数的含义铺垫了这么多,终于可以进入正题说说acks参数的含义了。如果不了解前面的拷贝机制、同步机制、ISR机制,那么就无法完全理解acks参数的含义。这个参数其实决定了很多重要的事情。首先在KafkaProducer中设置acks参数,即生产者客户端。也就是说,当你向Kafka写入数据时,你可以设置acks参数。那么这个参数其实有三个常用的值可以设置,分别是:0、1和all。第一个方案是把acks参数设置为0,也就是说我的KafkaProducer在客户端,只要消息发出去,不管数据有没有落到PartitionLeader上的盘上,我不用管他,直接就认为消息发送成功。如果你使用这个设置,那么你一定要注意,你发送的消息可能还在中途。结果PartitionLeader所在的Broker直接挂掉了,结果你的client还以为消息发送成功了,会导致消息丢失。第二种方案是设置acks=1,也就是说只要PartitionLeader收到消息并写入本地磁盘,就认为成功了,不管他的其他follower是否已经同步了消息。这个设置其实是Kafka的默认设置。敬请关注,重点关注!这是默认设置。也就是说,默认情况下,如果不关心acks参数,只要PartitionLeader写入成功,就认为成功。但是这里有一个问题。万一PartitionLeader刚收到消息,Follower还没来得及同步过去。结果Leader所在的broker宕机了,这个时候这条消息也会丢失,因为client已经认为send成功了。.最后一种情况是设置acks=all,也就是说PartitionLeader收到消息后,还必须要求ISR列表中与Leader同步的那些Follower同步消息,这样消息才能被认为写作成功。如果PartitionLeader刚刚收到消息,而Follower没有收到消息,此时Leader宕机,那么client就会感知到消息没有发送成功,会再次尝试发送消息。这时候Partition2的Follower可能会成为Leader。此时ISR列表中只有最新的Follower成为了Leader,所以只要新的Leader收到消息,就认为成功了。7.最后想到acks=all可以表示数据不会丢失吗?当然不是,如果你的Partition只有一份,也就是一个Leader,没有任何Follower,你觉得acks=all有用吗?当然是没用的,因为ISR中只有一个Leader,收到消息后会crash,也会造成数据丢失。所以这个acks=all必须配合至少两份ISR列表一起使用,至少一份Leader和一份Follower。只有这样才能保证在写一条数据的时候,如果收到了两份以上就一定是成功的。这时候数据的任何一个副本都会宕机,数据不会丢失。所以希望大家能够好好的看懂这篇文章。对大家出门面试或者工作使用kafka都会有很好的帮助。
