kafka 副本机制

287 阅读2分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

先复习一下相关概念:

  1. 副本

    • 副本是相对分区而言,即副本是特定分区的副本
    • 一个分区包含多个副本,副本分布在不同的 broker 中
    • 其中一个为 leader 副本,其余为 follower 副本
    • leader 副本对为提供读写服务,follower 副本只提供同步备份,不对外提供服务
  2. AR/ISR

    • 分区中所有副本统称 AR
    • 其中与 leader 副本保持同步状态的副本集合 → ISR ⇒ [leader, sync followers]
  3. LEO/HW

    • LEO 标示每个分区中下一条消息的写入点 → 每一个分区副本都有自己的LEO
    • ISR 中最小的 LEO ⇒ HW,俗称高水位,消费者只能拉取 HW 之前的代码

producer send msg 会发生什么?

→ send(msg)

→ 写入分区的 leader 副本中,需要等待 ISR 中的 follower 都同步完毕,才能被认为是已经提交,然后更新该分区的 HW

→ 消费者才能开始消费此 msg

LEO 与 HW

首先对于分区副本,最重要的是消息写入/消费。

消费写入 → LEO,每一个分区副本都有一个 LEO;follower 和 leader 同步 LEO 和 ISR 有关系

消费消费 → HW,根据每一个副本 LEO 来确定 leader HW (只有 leader 才有读写服务,所有 leader HW 才有被 consumer 消费的机会)

这里总结一下,leader/follower LEO 以及 HW 更新原则:

LEO 更新

leader:

  • producer send msg → leader 写入本地磁盘,LEO+1

leader remote:

  • follower fetch request → leader 过程中发生
  • 在 fetch req 中会携带 follower 要从哪个 offset 开始拉取 msg ⇒ pull offset = remote LEO

follower:

  • follower fetch request → leader 过程中发生
  • fetch 到 follower ,紧接着写入本地磁盘,LEO+1

HW 更新

leader:

  • leader 更新 LEO 后
  • 更新完 remote follower LEO 之后 ⇒ min{leader LEO, sync follower remote LEO...}

follower:

  • fetch req → follower 收到 resp {msg, leader HW},更新本地 LEO 之后
  • follower HW = min{follower LEO, remote leader HW}

在 HW 更新机制下,需要两轮才可以更新完毕:

  1. follower fetch msg → 获取到新的 msg ,更新本地 msg,LEO+1

  2. follower fetch req → 获取下一条 msg,发送自己当前LEO

    • leader update remote follower LEO ⇒ leader update HW
    • leader send resp{leader HW}follower updater HW

这样才更新完两边的 LEO/HW

为什么不支持读写分离

我们想想支持 读写分离 的组件:mysql。

mysql 主从数据在同步过程存在一个数据延延时的时间窗口,在这个窗口主从节点数据不一致。

kafka 如果在进行主从同步,需要:

**net I/O → leader mem → leader disk → net I/O → follower mem → follower disk**

从网络 → 磁盘 → 网络,整个过程延时大,对与 kafka 这种实时性要求的组件,不太合适。

总结:

  1. 同步过程中,出现数据不一致的时间窗口
  2. 同步延时高