这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
先复习一下相关概念:
-
副本
- 副本是相对分区而言,即副本是特定分区的副本
- 一个分区包含多个副本,副本分布在不同的 broker 中
- 其中一个为 leader 副本,其余为 follower 副本
- leader 副本对为提供读写服务,follower 副本只提供同步备份,不对外提供服务
-
AR/ISR
- 分区中所有副本统称 AR
- 其中与 leader 副本保持同步状态的副本集合 → ISR ⇒
[leader, sync followers]
-
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 更新机制下,需要两轮才可以更新完毕:
-
follower fetch msg → 获取到新的 msg ,更新本地 msg,LEO+1
-
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 这种实时性要求的组件,不太合适。
总结:
- 同步过程中,出现数据不一致的时间窗口
- 同步延时高