Kafka 生产者 ack、min.insync.replicas、replication factor机制剖析

Kafka 有三个很重要的配置参数,acksmin.insync.replicas.以及replication factor 其中acks是 producer 的配置参数,min.insync.replicas是 Broker 端的配置参数,这三个参数对于生产者不丢失数据起到了很大的作用.

一、分区副本


1、Kafka 的 topic 是可以分区的,并且可以为分区配置多个副本,改配置可以通过replication.factor参数实现.

2、Kafka 中的分区副本包括两种类型:领导者副本(Leader Replica)和追随者副本(Follower Replica),每个分区在创建时都要选举一个副本作为领导者副本,其余的副本自动变为追随者副本.

3、在 Kafka 中,追随者副本是不对外提供服务的,也就是说,任何一个追随者副本都不能响应消费者和生产者的读写请求. 所有的请求都必须由领导者副本来处理. 换句话说,所有的读写请求都必须发往领导者副本所在的 Broker,由该 Broker 负责处理. 追随者副本不处理客户端请求,它唯一的任务就是从领导者副本异步拉取消息,并写入到自己的提交日志中,从而实现与领导者副本的同步.

4、Kafka 默认的副本因子replication.factor是 3,即每个分区只有 1 个 leader 副本和 2 个 follower 副本. 具体如下图所示:

5、上面提到生产者客户端仅写入 Leader broker,跟随者异步复制数据。由于 Kafka 是一个分布式系统,必然会存在与 Leader 不能实时同步的风险,所以需要一种方法来判断这些追随者是否跟上了领导者的步伐, 即追随者是否同步了最新的数据. 换句话说,Kafka 要明确地告诉我们,追随者副本到底在什么条件下才算与 Leader 同步?这就是下面所要说的 ISR 同步副本机制.

二、同步副本 (In-sync replicas)


1、In-sync replica(ISR) 称之为同步副本,ISR 中的副本都是与 Leader 进行同步的副本,所以不在该列表的 follower 会被认为与 Leader 是不同步的. 那么,ISR 中存在是什么副本呢?首先可以明确的是:Leader 副本总是存在于 ISR 中. 而 follower 副本是否在 ISR 中,取决于该 follower 副本是否与 Leader 副本保持了 “同步”.

尖叫提示:对于 “follower 副本是否与 Leader 副本保持了同步” 的理解如下:

1、上面所说的同步不是指完全的同步,即并不是说一旦 follower 副本同步滞后与 Leader 副本,就会被踢出 ISR 列表.

2、Kafka 的 broker 端有一个参数replica.lag.time.max.ms, 该参数表示 follower 副本滞后与 Leader 副本的最长时间间隔,默认是 10 秒. 这就意味着,只要 follower 副本落后于 leader 副本的时间间隔不超过 10 秒,就可以认为该 follower 副本与 leader 副本是同步的,所以哪怕当前 follower 副本落后于 Leader 副本几条消息,只要在 10 秒之内赶上 Leader 副本,就不会被踢出出局.

扫描二维码关注公众号,回复: 17241575 查看本文章

3、如果 follower 副本被踢出 ISR 列表,等到该副本追上了 Leader 副本的进度,该副本会被再次加入到 ISR 列表中,所以 ISR 是一个动态列表,并不是静态不变的。

2、如上图所示:Broker3 上的 partition1 副本超过了规定时间,未与 Leader 副本同步,所以被踢出 ISR 列表,此时的 ISR 为 [1,3].

三、acks 确认机制


1、acks 参数指定了必须要有多少个分区副本收到消息,生产者才认为该消息是写入成功的,这个参数对于消息是否丢失起着重要作用,该参数的配置具体如下:

  • acks=0,表示生产者在成功写入消息之前不会等待任何来自服务器的响应. 换句话说,一旦出现了问题导致服务器没有收到消息,那么生产者就无从得知,消息也就丢失了. 改配置由于不需要等到服务器的响应,所以可以以网络支持的最大速度发送消息,从而达到很高的吞吐量。

  • acks=1,表示只要集群的 leader 分区副本接收到了消息,就会向生产者发送一个成功响应的 ack,此时生产者接收到 ack 之后就可以认为该消息是写入成功的. 一旦消息无法写入 leader 分区副本 (比如网络原因、leader 节点崩溃), 生产者会收到一个错误响应,当生产者接收到该错误响应之后,为了避免数据丢失,会重新发送数据. 这种方式的吞吐量取决于使用的是异步发送还是同步发送.

    尖叫提示:如果生产者收到了错误响应,即便是重新发消息,还是会有可能出现丢数据的现象. 比如,如果一个没有收到消息的节点成为了新的 Leader,消息就会丢失.

  • acks =all, 表示只有所有参与复制的节点 (ISR 列表的副本) 全部收到消息时,生产者才会接收到来自服务器的响应. 这种模式是最高级别的,也是最安全的,可以确保不止一个 Broker 接收到了消息. 该模式的延迟会很高.

四、最小同步副本


1、上面提到,当 acks=all 时,需要所有的副本都同步了才会发送成功响应到生产者. 其实这里面存在一个问题:如果 Leader 副本是唯一的同步副本时会发生什么呢?此时相当于 acks=1. 所以是不安全的.

2、Kafka 的 Broker 端提供了一个参数min.insync.replicas, 该参数控制的是消息至少被写入到多少个副本才算是 “真正写入”, 该值默认值为 1,生产环境设定为一个大于 1 的值可以提升消息的持久性. 因为如果同步副本的数量低于该配置值,则生产者会收到错误响应,从而确保消息不丢失.

4.1、Case 1

1、如下图,当 min.insync.replicas=2 且 acks=all 时,如果此时 ISR 列表只有 [1,2],3 被踢出 ISR 列表,只需要保证两个副本同步了,生产者就会收到成功响应.

4.2、 Case 2

1、如下图,当 min.insync.replicas=2,如果此时 ISR 列表只有 [1],2 和 3 被踢出 ISR 列表,那么当 acks=all 时,则不能成功写入数;当 acks=0 或者 acks=1 可以成功写入数据.

4.3、Case 3

1、这种情况是很容易引起误解的,如果 acks=all 且 min.insync.replicas=2,此时 ISR 列表为 [1,2,3], 那么还是会等到所有的同步副本都同步了消息,才会向生产者发送成功响应的 ack. 因为 min.insync.replicas=2 只是一个最低限制,即同步副本少于该配置值,则会抛异常,而 acks=all,是需要保证所有的 ISR 列表的副本都同步了才可以发送成功响应. 如下图所示:

五、总结


  • acks=0,生产者在成功写入消息之前不会等待任何来自服务器的响应.

  • acks=1, 只要集群的 leader 分区副本接收到了消息,就会向生产者发送一个成功响应的 ack.

  • acks=all, 表示只有所有参与复制的节点 (ISR 列表的副本) 全部收到消息时,生产者才会接收到来自服务器的响应,此时如果 ISR 同步副本的个数小于min.insync.replicas的值,消息不会被写入.

原文地址:Kafka 生产者 ack 机制剖析

猜你喜欢

转载自blog.csdn.net/qq_38263083/article/details/133121727