本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力
先复习一下相关概念:
-
副本
- 副本是相对分区而言,即副本是特定分区的副本
- 一个分区包含多个副本,副本分布在不同的 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
Epoch 机制
leader epoch 并没有改变 HW 机制的整体运行,改进的只是 leader/follower 重启恢复后的日志截断动作
为什么不支持读写分离
我们想想支持 读写分离 的组件:mysql。
mysql 主从数据在同步过程存在一个数据延延时的时间窗口,在这个窗口主从节点数据不一致。
kafka 如果在进行主从同步,需要:
net I/O → leader mem → leader disk → net I/O → follower mem → follower disk
从网络 → 磁盘 → 网络,整个过程延时大,对与 kafka 这种实时性要求的组件,不太合适。
其次在主从同步里面,最明显的问题就是:read sync msg → 就是我在副本是不能立马读到 msg,这个和前面说的有时间窗口一个意思 ⇒ 方便 read what you write
在副本同步过程中,如果允许 副本读 → 很可能会引起 副本间数据同步延时 :在 A 中以及同步,目前可读;但是在 B 中正在同步 leader,就会出现 msg 时而可读时而不可读。
总结:
- 同步过程中,出现数据不一致的时间窗口
- 同步延时高
- 方便实现 Read-What-You-Write
- 方便实现 Monotonic Reads
但是,虽然副本不可读,但是副本本身的职责:同步 leader 数据,这个得保障 → 它们的动作就是不断异步拉取 leader 副本的数据。
既然是异步的,那么在一定时间内,leader 和 follower 的数据肯定是不一致的 (这个也是为什么 follower 不可读的又一个证明) ,那我们应该怎么定义 leader 和 follower 之间同步的标准?
因为只有知道标准,server 才认为 msg 已经在副本间备份完毕,才不会有数据丢失的可能 (当然了,如果 server 存储的磁盘都没有了,数据肯定丢失了。此处 “丢失” 指的是正常情况)
此处就引出:ISR → In-sync Replicas ⇒ ISR 中的副本都是与 Leader 同步的副本






















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)