Kafka 进阶学习(十六)—— 副本

181 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情

前言

今天是我 Kafka 学习的第 16 天,今天学习的内容是副本。

副本(Replica)是分布式系统中常见的概念之一,指的是分布式系统对数据和服务提供的一种冗余方式。Kafka 通过多副本机制实现故障自动转移。

下面开始我们今天的学习之旅!

基本概念

在开始学习之前,我们先学习一些和副本相关的基本概念。

leader 副本和 follow 副本

副本是相对于分区而言的,即副本是特定分区的副本。

一个分区中包含一个或多个副本,其中一个为 leader 副本,其余为 follower 副本,各个副本位于不同的 broker 节点中。只有 leader 副本对外提供服务,follower 副本只负责数据同步。

AR 和 ISR

分区中的所有副本统称为 AR(Assigned Repllicas),而 ISR(In-Sync Replicas) 是指与leader 副本保持同步状态的副本集合,当然 leader 副本本身也是这个集合中的一员。ISR 集合是 AR 集合中的一个子集。

LEO 和 HW

LEO(Log End Offset的)表示了当前日志文件中下一条待写入消息的 offset,LEO 的大小相当于当前日志分区中最后一条消息的 offset 值加 1。分区 ISR 集合中的每个副本都会维护自身的 LEO,而 ISR 集合中最小的 LEO 即为分区的 HW,对消费这而言只能消费 HW 之前的消息。

失效副本和失效分区

正常情况下,分区的所有副本都处于 ISR 集合中,但是难免会有异常情况发生,从而某些副本被剥离出 ISR 集合中。在 ISR 集合之外,也就是处于同步失效或功能失效(比如副本处于非存活状态)的副本统称为失效副本,失效副本对应的分区也就称为同步失效分区,即 under-replicated 分区。

失效副本不仅是指处于功能失效状态的副本,处于同步失效状态的副本也可以看作失效副本。Kafka 通过唯一的 broker 端参数 replica.lag.time.max.ms 来判断一个副本是否为同步实效副本,当 ISR 集合中的一个 follower 副本滞后 leader 副本的时间超过此参数指定的值时则判定为同步失败,需要将此 follower 副本剔除出 ISR 集合。replica.lag.time.max.ms 参数的默认值为 10000。

其实现原理为:当 follower 副本将 leader 副本 LEO(LogEndOffset)之前的日志全部同步时,则认为该 follower 副本已经追赶上 leader 副本,此时更新该副本的 lastCaughtUpTimeMs 标识。

Kafka 的副本管理器会启动一个副本过期检测的定时任务,而这个定时任务会定时检查当前时间与副本的 lastCaughtUpTimeMs 差值是否大于参数 replica.lag.time.max.ms 指定的值。

注意:follower 副本 拉取 leader 副本的数据不一定就会更新 lastCaughtUpTimeMs。  试想一下,当 leader 副本中消息的流入速度大于 follower 副本中拉取的速度时,就算 follower 副本一直不断地拉取 leader 副本的消息也不能与 leader 副本同步。如果还将此 follower 副本置于 ISR 集合中,那么当 leader 副本下线而选取此 follower 副本为新的 leader 副本时就会造成消息的严重丢失。

一般有两种情况会导致副本失效:

  • follower 副本进程卡住,在一段时间内根本没有向 leader 副本发起同步请求,比如频繁的 Full GC。
  • follower 副本进程同步过慢,在一段时间内都无法追赶上 leader 副本,比如 I/O 开销过大。

ISR 扩缩容

缩容

Kafka 在启动的时候会开启两个与 ISR 相关的定时任务,名称分别为“isr-expiration”和“isr-change-propagation”。isr-expiration 任务会周期性地检测每个分区是否需要缩减其 ISR 集合。当检测到 ISR 集合中有失效副本时,就会收缩 ISR 集合。

如果某个分区的 ISR 集合发生变更,则会将变更后的数据记录到 ZooKeeper 对应的 /brokers/topics/<topic>/partition/<parititon>/state 节点中。

除此之外,当 ISR 集合发生变更时还会将变更后的记录缓存到 isrChangeSet 中,isr-change-propagation 任务会周期性(固定值为 2500ms)地检查 isrChangeSet,如果发现 isrChangeSet 中有 ISR 集合的变更记录,那么它会在 ZooKeeper的 /isr_change_notification 路径下创建一个以 isr_change_开头的持久顺序节点并将 isrChangeSet 中的信息保存到这个节点中。

Kafka控 制器为 /isr_change_notification 添加了一个 Watcher,当这个节点中有子节点发生变化时会触发 Watcher 的动作,以此通知控制器更新相关元数据信息并向它管理的 broker 节点发送更新元数据的请求,最后删除 /isr_change_notification 路径下已经处理过的节点。

注意:频繁地触发 Watcher 会影响 Kafka 控制器、ZooKeeper 甚至其他 broker 节点的性能。为了避免这种情况,Kafka 添加了限定条件,当检测到分区的 ISR 集合发生变化时,还需要检查以下两个条件:

  1. 上一次 ISR 集合发生变化距离现在已经超过 5s。
  2. 上一次写入 ZooKeeper 的时间距离现在已经超过 60s。

满足以上两个条件之一才可以将 ISR 集合的变化写入目标节点。

扩容

随着 follower 副本不断与 leader 副本进行消息同步,follower 副本的 LEO 也会逐渐后移,并最终追赶上 leader 副本,此时该 follower 副本就有资格进入 ISR 集合。

追赶上 leader 副本的判定准则是此副本的 LEO 是否不小于 leader 副本的 HW

参考文档

  • 《深入理解 Kafka:核心设计与实践原理》—— 朱忠华

往期文章