(0)写在前面面试
(1)如何保证宕机时数据不丢失?redis
(2)多副本冗余的高可用机制架构
(3)多副本之间数据如何同步?elasticsearch
(4)ISR到底指的什么东西?分布式
(5)acks参数的含义?学习
(6)最后的思考3d
我的公众号:石杉的架构笔记(ID:shishan100)cdn
面试大厂时,一旦简历上写了Kafka,几乎必然会被问到一个问题:说说acks参数对消息持久化的影响?blog
这个acks参数在kafka的使用中,是很是核心以及关键的一个参数,决定了不少东西。kafka
因此不管是为了面试仍是实际项目使用,你们都值得看一下这篇文章对Kafka的acks参数的分析,以及背后的原理。
若是要想理解这个acks参数的含义,首先就得搞明白kafka的高可用架构原理。
好比下面的图里就是代表了对于每个Topic,咱们均可以设置他包含几个Partition,每一个Partition负责存储这个Topic一部分的数据。
而后Kafka的Broker集群中,每台机器上都存储了一些Partition,也就存放了Topic的一部分数据,这样就实现了Topic的数据分布式存储在一个Broker集群上。
可是有一个问题,万一 一个Kafka Broker宕机了,此时上面存储的数据不就丢失了吗?
没错,这就是一个比较大的问题了,分布式系统的数据丢失问题,是他首先必需要解决的,一旦说任何一台机器宕机,此时就会致使数据的丢失。
因此若是你们去分析任何一个分布式系统的原理,好比说zookeeper、kafka、redis cluster、elasticsearch、hdfs,等等,其实他都有本身内部的一套多副本冗余的机制,多副本冗余几乎是如今任何一个优秀的分布式系统都通常要具有的功能。
在kafka集群中,每一个Partition都有多个副本,其中一个副本叫作leader,其余的副本叫作follower,以下图。
如上图所示,假设一个Topic拆分为了3个Partition,分别是Partition0,Partiton1,Partition2,此时每一个Partition都有2个副本。
好比Partition0有一个副本是Leader,另一个副本是Follower,Leader和Follower两个副本是分布在不一样机器上的。
这样的多副本冗余机制,能够保证任何一台机器挂掉,都不会致使数据完全丢失,由于起码仍是有副本在别的机器上的。
接着咱们就来看看多个副本之间数据是如何同步的?其实任何一个Partition,只有Leader是对外提供读写服务的
也就是说,若是有一个客户端往一个Partition写入数据,此时通常就是写入这个Partition的Leader副本。
而后Leader副本接收到数据以后,Follower副本会不停的给他发送请求尝试去拉取最新的数据,拉取到本身本地后,写入磁盘中。以下图所示:
既然你们已经知道了Partiton的多副本同步数据的机制了,那么就能够来看看ISR是什么了。
ISR全称是“In-Sync Replicas”,也就是保持同步的副本,他的含义就是,跟Leader始终保持同步的Follower有哪些。
你们能够想一下 ,若是说某个Follower所在的Broker由于JVM FullGC之类的问题,致使本身卡顿了,没法及时从Leader拉取同步数据,那么是否是会致使Follower的数据比Leader要落后不少?
因此这个时候,就意味着Follower已经跟Leader再也不处于同步的关系了。可是只要Follower一直及时从Leader同步数据,就能够保证他们是处于同步的关系的。
因此每一个Partition都有一个ISR,这个ISR里必定会有Leader本身,由于Leader确定数据是最新的,而后就是那些跟Leader保持同步的Follower,也会在ISR里。
铺垫了那么多的东西,最后终于能够进入主题来聊一下acks参数的含义了。
若是你们没看明白前面的那些副本机制、同步机制、ISR机制,那么就没法充分的理解acks参数的含义,这个参数实际上决定了不少重要的东西。
首先这个acks参数,是在KafkaProducer,也就是生产者客户端里设置的
也就是说,你往kafka写数据的时候,就能够来设置这个acks参数。而后这个参数实际上有三种常见的值能够设置,分别是:0、1 和 all。
第一种选择是把acks参数设置为0,意思就是个人KafkaProducer在客户端,只要把消息发送出去,无论那条数据有没有在哪怕Partition Leader上落到磁盘,我就无论他了,直接就认为这个消息发送成功了。
若是你采用这种设置的话,那么你必须注意的一点是,可能你发送出去的消息还在半路。结果呢,Partition Leader所在Broker就直接挂了,而后结果你的客户端还认为消息发送成功了,此时就会致使这条消息就丢失了。
第二种选择是设置 acks = 1,意思就是说只要Partition Leader接收到消息并且写入本地磁盘了,就认为成功了,无论他其余的Follower有没有同步过去这条消息了。
这种设置实际上是kafka默认的设置,你们请注意,划重点!这是默认的设置
也就是说,默认状况下,你要是无论acks这个参数,只要Partition Leader写成功就算成功。
可是这里有一个问题,万一Partition Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了,此时也会致使这条消息丢失,由于人家客户端已经认为发送成功了。
最后一种状况,就是设置acks=all,这个意思就是说,Partition Leader接收到消息以后,还必需要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。
若是说Partition Leader刚接收到了消息,可是结果Follower没有收到消息,此时Leader宕机了,那么客户端会感知到这个消息没发送成功,他会重试再次发送消息过去。
此时可能Partition 2的Follower变成Leader了,此时ISR列表里只有最新的这个Follower转变成的Leader了,那么只要这个新的Leader接收消息就算成功了。
acks=all 就能够表明数据必定不会丢失了吗?
固然不是,若是你的Partition只有一个副本,也就是一个Leader,任何Follower都没有,你认为acks=all有用吗?
固然没用了,由于ISR里就一个Leader,他接收完消息后宕机,也会致使数据丢失。
因此说,这个acks=all,必须跟ISR列表里至少有2个以上的副本配合使用,起码是有一个Leader和一个Follower才能够。
这样才能保证说写一条数据过去,必定是2个以上的副本都收到了才算是成功,此时任何一个副本宕机,不会致使数据丢失。
因此但愿你们把这篇文章好好理解一下,对你们出去面试,或者工做中用kafka都是很好的一个帮助。
欢迎关注公众号:石杉的架构笔记,公众号后台回复资料,获取做者独家秘制学习资料
石杉的架构笔记,BAT架构经验倾囊相授