kafka的ACK参数的详解和配置建议

面试的时候,一旦简历上写了Kafka,几乎必然会被问到一个问题:说说acks参数对消息持久化的影响?

这个acks参数在kafka的使用中,是非常核心以及关键的一个参数,决定了很多东西。所以无论是为了面试还是实际项目使用,大家都值得看一下这篇文章对Kafka的acks参数的分析,以及背后的原理

一、kafka的ACK参数-1,0,1分别代表的含义

这个acks参数在kafka的使用中,是非常核心以及关键的一个参数,决定了很多东西,Kafka producer有三种ack机制 初始化producer时在config中进行配置

ack等于0:意味着producer不等待broker同步完成的确认,继续发送下一条(批)信息

提供了最低的延迟。但是最弱的持久性,当服务器发生故障时,就很可能发生数据丢失。例如leader已经死亡,producer不知情,还会继续发送消息broker接收不到数据就会数据丢失。

ack等于1(默认):意味着producer要等待leader成功收到数据并得到确认,才发送下一条message。此选项提供了较好的持久性较低的延迟性。artition的Leader死亡,follwer尚未复制,数据就会丢失。

img

ack等于-1:意味着producer得到follwer确认,才发送下一条数据,持久性最好,延时性最差。

img

0,1,-1三种机制性能递减,可靠性递增

二、如何保证宕机的时候数据不丢失?

如果要想理解这个acks参数的含义,首先就得搞明白kafka的高可用架构原理。比如下面的图里就是表明了对于每一个Topic,我们都可以设置他包含几个Partition,每个Partition负责存储这个Topic一部分的数据。然后kafka通常采用了多副本冗余的高可用机制。在kafka集群中,每个Partition都有多个副本,其中一个副本叫做leader,其他的副本叫做follower。

假设一个Topic拆分为了3个Partition,分别是Partition0,Partiton1,Partition2,此时每个Partition都有2个副本。比如Partition0有一个副本是Leader,另外一个副本是Follower,Leader和Follower两个副本是分布在不同机器上的。这样的多副本冗余机制,可以保证任何一台机器挂掉,都不会导致数据彻底丢失,因为起码还是有副本在别的机器上的。

img

Kafka的Broker集群中,每台机器上都存储了一些Partition,也就存放了Topic的一部分数据,这样就实现了Topic的数据分布式存储在一个Broker集群上。但是有一个问题,万一有一个Kafka Broker宕机了,此时上面存储的数据不就丢失了吗?

没错,这就是一个比较大的问题了,分布式系统的数据丢失问题,是他首先必须要解决的,一旦说任何一台机器宕机,此时就会导致数据的丢失。

三、多副本冗余的高可用机制

所以如果大家去分析任何一个分布式系统的原理,比如说zookeeper、kafka、redis cluster、elasticsearch、hdfs,等等,其实他都有自己内部的一套多副本冗余的机制,多副本冗余几乎是现在任何一个优秀的分布式系统都一般要具备的功能。

在kafka集群中,每个Partition都有多个副本,其中一个副本叫做leader,其他的副本叫做follower,如下图。

img

如上图所示,假设一个Topic拆分为了3个Partition,分别是Partition0,Partiton1,Partition2,此时每个Partition都有2个副本。

比如Partition0有一个副本是Leader,另外一个副本是Follower,Leader和Follower两个副本是分布在不同机器上的。

这样的多副本冗余机制,可以保证任何一台机器挂掉,都不会导致数据彻底丢失,因为起码还是有副本在别的机器上的。

四、多副本之间数据如何同步?

接着我们就来看看多个副本之间数据是如何同步的?其实任何一个Partition,只有Leader是对外提供读写服务的

也就是说,如果有一个客户端往一个Partition写入数据,此时一般就是写入这个Partition的Leader副本。

然后Leader副本接收到数据之后,Follower副本会不停的给他发送请求尝试去拉取最新的数据,拉取到自己本地后,写入磁盘中。如下图所示:

img

五、ISR到底指的是什么东西?

既然大家已经知道了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参数的含义

铺垫了那么多的东西,最后终于可以进入主题来聊一下acks参数的含义了。

如果大家没看明白前面的那些副本机制、同步机制、ISR机制,那么就无法充分的理解acks参数的含义,这个参数实际上决定了很多重要的东西。

首先这个acks参数,是在KafkaProducer,也就是生产者客户端里设置的

也就是说,你往kafka写数据的时候,就可以来设置这个acks参数。然后这个参数实际上有三种常见的值可以设置,分别是:0、1 和 all。

第一种选择是把acks参数设置为0,意思就是我的KafkaProducer在客户端,只要把消息发送出去,不管那条数据有没有在哪怕Partition Leader上落到磁盘,我就不管他了,直接就认为这个消息发送成功了。

如果你采用这种设置的话,那么你必须注意的一点是,可能你发送出去的消息还在半路。结果呢,Partition Leader所在Broker就直接挂了,然后结果你的客户端还认为消息发送成功了,此时就会导致这条消息就丢失了。

img

第二种选择是设置 acks = 1,意思就是说只要Partition Leader接收到消息而且写入本地磁盘了,就认为成功了,不管他其他的Follower有没有同步过去这条消息了。

img

这种设置其实是kafka默认的设置,大家请注意,划重点!这是默认的设置

也就是说,默认情况下,你要是不管acks这个参数,只要Partition Leader写成功就算成功。

但是这里有一个问题,万一Partition Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了,此时也会导致这条消息丢失,因为人家客户端已经认为发送成功了。

最后一种情况,就是设置acks=all,这个意思就是说,Partition Leader接收到消息之后,还必须要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。

img

如果说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都是很好的一个帮助。

八、最佳实践

结论

  1. 三节点集群建议配置 replication.factor = 2 、 min.insync.replicas = 2,理由如下:

    1. replication.factor 2 的话相较于 replication.factor 3 节省 1/3 磁盘空间,同时又保证了数据的备份。
    2. 影响:
      1. 一台机器出了问题,客户有感知,producer 无法正常写入数据,consumer 可以正常消费数据。
      2. 两台机器出了问题,客户有感知,producer 无法正常写入数据,consumer 无法正常消费数据。
      3. 结合下方合适的 producer 参数,可以做到数据不丢不重。
  2. HA 配**置 建议配置 replication.factor = 3 、 min.insync.replicas = 2,**

    1. 影响:
      1. 一台机器出了问题,客户无感知,producer 可以正常写入数据,consumer 可以正常消费数据。
      2. 两台机器出了问题,客户有感知,producer 无法正常写入数据,consumer 可以正常消费数据
  3. producer 建议配置:

    1. kafka client version > 1.1.1
      1. delivery.timeout.ms 配置 1200000 (20分钟),retries 配置无限重试, retry.backoff.ms 配置 15s,max.block.ms 配置 20分钟,acks = all,enable.idempotence=true,batch.size = 524288。
    1. kafka client version <= 1.1.1
      1. request.timeout.ms 配置 5 分钟,retries 配置次数 30, retry.backoff.ms 配置 15s,max.block.ms 配置 20分钟,acks = all,enable.idempotence=true,batch.size = 524288。

参数含义

  • replication.factor:这个参数代表 topic 的 副本数,1,代表着一个副本,即数据没有备份,2,代表着两个副本,意味着数据有一份备份,数字越大,意味着备份的副本数越多,相应的,也会占用更大的磁盘空间。以目前实践来看,如果把三节点集群replica 配置为 2,即既尽可能减少数据占用磁盘的容量,又保证了数据的备份。

  • min.insync.replicas:这个参数代表 ISR集合中的最少副本数,默认值是1,并只有在 acks=all 或 -1 时才有效。

    • acks 与 min.insync.replicas 搭配使用,才能为消息提供最高的持久性保证。我们知道leader副本默认就包含在ISR中,如果 ISR 中只有1个副本,acks=all 也就相当于 acks=1 了,引入 min.insync.replicas 的目的就是为了保证下限:不能只满足于ISR全部写入,还要保证ISR中的写入个数不少于 min.insync.replicas。
    • 常见的场景是创建一个三副本(即 replication.factor=3)的topic,最少同步副本数设为2(即 min.insync.replicas=2),acks设为all,以保证最高的消息持久性。

broker参数合理配置

环境 replication.factor min.insync.replicas 备注
单机 1 1 单机 replication.factor 和 min.insync.replicas 只能配 1
3节点集群 2 2 3节点集群replication.factor 建议配置为 2,replication.factor 不配置为 3 或者 1 的原因是:#1 replication.factor 2 的话会节省很多的磁盘空间同时又保证了数据的备份#2 如果配置为 3,如果 MINI 集群有节点坏了后,如果想通过先减一个节点,再加一个节点,达到换节点的目的,那么相应 topic 的数据没有办法 reassign min.insync.replicas 建议配置为 2保证数据写入至少有一份备份才会写入成功,这样 leader down 了,也不会丢数据注意如果可以承担丢失少量数据或者写入数据重复的风险且对服务可用性要求比较高的话,可以配置 min.insync.replicas 为 1 且配置重试,这样一台 broker down 了,还是可以继续工作的
HA 配置(场景:有些客户集群部署了很多的 kafka broke,有时候 down 掉个一台,希望客户无感知,down 掉两台希望数据不丢) 3 2 replication.factor 建议配置为 3min.insync.replicas 建议配置为 2,经过这样配置后,可以保证,一台机器出了问题,客户无感知,两台机器出了问题,数据不丢。代价:#1 要做到无感知,kafka producer 需要配置上重试,可能会带来数据的重复。#2 对磁盘容量的要求是 replication.factor 为 2 的 1.5 倍

client 配置影响,其中 broker 配置如上

结论:

  1. 在未上 HA 配置之前,按照 MINI 集群、标准集群的配置,down 掉一台 broker,客户都会感知到。因此,推荐发送端可以不开启重试或者幂等。
  2. HA 配置,理论上是希望客户down 掉一台 broker, 客户无感知,down 掉两台,数据不丢不重,因此,HA 配置,是需要开启幂等和重试的,除此之外,**发送数据端也要具备**跨 producer 生命周期的数据去重以及继续发送,否则 client 出了问题,还是没办法保证幂等的。
环境 重试 幂等 acks=-1 (不填,则 acks 设 1) 损坏机器数 造成影响 producer client consumer client 数据安全
单机 / / / 1 主要分为:producer clientconsumer client数据安全对 producer client 造成的影响指的是:无法正常写入数据对 consunmer client 造成的影响指的是:无法正常写入数据数据安全造成的影响指的是:数据重复或者数据丢失 #1 无法正常写入数据#2 客户端抛异常退出 #1 无法正常消费数据#2 客户端抛异常退出 客户有感知,数据小概率丢失或者重复
MINI 集群 / / / 1 #1 涉及损坏机器 broker id 的 topic partitions无法正常写入数据 #1 可以正常消费数据 客户有感知,数据小概率丢失或者重复
/ / 1 #1 涉及损坏机器 broker id 的 topic partitions无法正常写入数据 #1 可以正常消费数据 客户有感知,数据小概率丢失或者重复
/ 1 #1 涉及损坏机器 broker id 的 topic partitions无法正常写入数据 #1 可以正常消费数据 客户有感知,数据小概率丢失或者重复
1 #1 涉及损坏机器 broker id 的 topic partitions无法正常写入数据 #1 可以正常消费数据 客户有感知,数据不丢不重
/ 2 #1 涉及损坏机器 broker id 的 topic partitions无法正常写入数据 #1 无法正常消费数据 客户有感知,数据不丢不重
HA 配置(场景:有些客户集群部署了很多的 kafka broke,有时候 down 掉个一台,希望客户无感知,down 掉两台希望数据不丢) / / / 1 #1 可以正常发送数据 #1 可以正常消费数据 客户有感知,数据小概率丢失或者重复
/ / 1 #1 可以正常发送数据 #1 可以正常消费数据 客户有感知,数据可能丢失或者重复
/ 1 #1 可以正常发送数据 #1 可以正常消费数据 客户无感知,数据小概率丢失或者重复
1 #1 可以正常发送数据 #1 可以正常消费数据 客户无感知,数据不丢不重
2 #1 涉及所有损坏机器 broker id 的 topic partitions无法正常写入数据 #1 可以正常消费数据 客户有感知,数据不丢不重

注意

表中的幂等,除了 kafka 本身 producer 开启的幂等外,发送数据端也要具备跨 producer 生命周期的数据去重以及继续发送,否则 client 出了问题,还是没办法保证幂等的。

参考文档:https://blog.csdn.net/weixin_60067160/article/details/123034255

------本页内容已结束,喜欢请分享------

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发
运维开发故事的头像-运维开发故事

昵称

取消
昵称表情代码图片