Follower 不是被动等 Leader 推送数据,而是主动向 Leader 发 Fetch 请求拉取。这次杀掉一个 Follower 所在的 Broker,在它缺席期间写入数据,再重启它,计时它追上 Leader、重新进入 ISR 需要多久。
命令 · shell $ kill -9 <broker1-pid> # broker1 是这个分区的 Follower,不是 Leader $ kafka-topics.sh --bootstrap-server 127.0.0.1:19292,127.0.0.1:19392 --describe --topic replica-sync-demo
Partition: 0 Leader: 2 Replicas: 2,3,1 Isr: 2,3
杀掉 broker1 后,ISR 立刻从 1,2,3 变成 2,3——broker1 被移出了"可以参与确认写入"的副本集合,即使它在 Replicas 列表里仍然存在(说明它理论上还是这个分区的副本,只是当前不同步)。这期间写入的 5000 行数据只被复制到了 broker2(Leader)和 broker3(还在线的 Follower)。
命令 · shell $ kafka.Kafka node1.properties & # 重启 broker1 # 每 0.5 秒轮询一次 ISR,直到 broker1 重新出现
t+15.37s ISR=1,2,3 broker1 重新加入 ISR
轮询发现,broker1 从进程重启到重新出现在 ISR 里,一共花了 15.37 秒——这包含了 JVM 启动、加载数据、和向 Leader 发起 Fetch 请求、拉取缺失数据(这次缺失了 5000 行)直到追平的完整过程。重新加入 ISR 之后,查三个 Broker 上这个分区的 Log End Offset,三边都是 10000,完全一致——不是"大概同步了",是核对过 offset 数字相等。
副本同步的机制是"拉"不是"推":Follower 主动向 Leader 发 Fetch 请求,跟不上时会被移出 ISR(不再参与 acks=all 的确认),重新跟上后再被加回来。这次测出的 15.37 秒不是一个通用数字(取决于缺失了多少数据、JVM 启动开销),但这个"掉线 → 移出 ISR → 拉取追赶 → 数据对齐 → 重新加入 ISR"的完整链路是走了一遍、用 offset 核对过一致性的,不是描述性的说法。
每一步都是本文上两节kill -9、写入数据、轮询ISR和核对offset得到的原始结果。