Theory · Kafka · Replication & Consistency
Kafka 副本机制与数据一致性
ISR · LEO/HW 水位 · HW 机制的两个经典缺陷 · KIP-101 LeaderEpoch · unclean 选举 · acks 矩阵 · KRaft 架构
复制协议核心
动态 ISR(f+1 容 f)替代多数派;HW=min(ISR 的 LEO) 划定消费者可见边界
一致性深挖
HW 截断的数据丢失与错位问题 → KIP-101 LeaderEpoch 截断校验;acks=all×min.insync.replicas 矩阵
KRaft 时代
为什么移除 ZooKeeper、Controller Quorum(Raft)与 __cluster_metadata,3.3→4.0 演进线
这份 deck 是 Kafka 可靠性的核心战场,也是面试最深挖的部分。主线:ISR 动态副本集怎么工作、LEO 和 HW 两个水位怎么定义、HW 截断机制为什么有数据丢失和日志错位两个经典缺陷、KIP-101 怎么修复、acks 和 min.insync.replicas 怎么配合、最后 KRaft 架构。所有默认值都对照 4.3 源码核过,两个 HW 缺陷的推演按 KIP-101 原始讨论整理。学完能扛住"acks=all 为什么还丢消息"这条追问链。
Replicas · AR / ISR / OSR
副本与角色:Leader 读写、Follower 拉取、ISR 动态集合
Leader
分区的读写入口:produce 永远发给 leader;消费默认读 leader(2.4 起可机架就近读 follower,见下)。所有 HW/LEO 的裁决在 leader 侧进行。
Follower
被动拉取复制:与普通消费者同一套 fetch 机制(天然成批、零拷贝复用)。只从 leader 拉,推复制不存在——follower 崩溃重启不污染 leader。
AR = ISR + OSR
ISR(in-sync replicas):追得上 leader 的副本集合(含 leader 自身);OSR:掉队被移出的。ISR 是动态的:收缩与回归都由 leader 维护,不重启生效。
| 追问 | 答案 |
| 怎么算"追上"? | replica.lag.time.max.ms=30000(4.3 源码):follower 至少 30s 没发 fetch、或没消费到 leader 日志末端 → 移出 ISR。旧版还看消息条数差(replica.lag.max.messages,已废弃) |
| 掉队副本怎么回归? | 恢复后先截断对齐(KIP-101 校验,第 7 页)→ 从 leader 全量补齐缺口 → 重新追平末端 → leader 自动拉回 ISR(unclean 选举无关,这是正常回归路径) |
| 为什么不用多数派写? | ISR 模型 f+1 副本容 f 故障:2 副本即容 1 台宕机(Raft/Paxo 需 2f+1=3)——磁盘与写放大省一半;代价是 acks=all 的提交延迟受最慢 ISR 成员影响 |
一句话:"ISR 是'当前有资格参与提交'的动态副本集——leader 维护、按追平度进出;数据正确性只依赖 ISR,不依赖 AR 全体。"
副本页立三个概念。Leader 是唯一读写入口,Follower 用和消费者一样的 fetch 拉取复制,这个设计让复制天然成批。AR 等于 ISR 加 OSR,ISR 是动态集合,进出都由 leader 按 30 秒追平窗口维护。三个追问:怎么算追上——30 秒内发过 fetch 且消费到末端;怎么回归——先截断对齐全量补齐再自动回 ISR,注意这和 unclean 选举无关;为什么不用多数派——f 加 1 容 f,两副本容一台宕机,省一半磁盘,代价是提交延迟受最慢成员拖累。
Shrink & Catch-up
一次完整的收缩-回归时间线:丢没丢,什么时候丢?
| 时刻 | 事件 | ISR / HW | 数据视角 |
| t0 | 3 副本全追平,producer 以 acks=all 写入 m10 | ISR={A,B,C} · HW=11 | m10 已提交:三副本都有(各自页缓存) |
| t1 | C 磁盘慢,lag 持续增长;producer 写 m11(acks=all 等到 A、B) | ISR={A,B}(C 超 30s 未追上 → 移出) | m11 提交于 {A,B};C 的日志停在 m10 |
| t2 | A 宕机,controller 从 ISR 选 B 为新 leader | ISR={B}(C 在 OSR) | m11 在 B 上完好——已提交数据没丢(all 只承诺 ISR,而 C 当时不在 ISR) |
| t3 | C 恢复:LeaderEpoch 校验后截断对齐 → 全量拉回 m11 → 追平末端 | leader 把 C 拉回:ISR={B,C} | C 上从未提交过的 m10 残差被安全截断;m11 补齐 |
关键判定:HW 只进不退
移出落后者后 min(ISR LEO) 只会不动或上移——ISR 收缩不会让"已可见"数据回退;acks=all 的承诺对象是提交时刻的 ISR,C 掉队期间写入的消息本来就不等 C。"丢"只会发生在承诺对象(ISR)本身缩小后的写入上——引出第 10 页的 min.insync.replicas 门禁。
KIP-392 follower fetching(一句话)
2.4 起:消费者与 follower 副本均可设置 client.rack,broker 按 rack 就近服务——跨机房部署时读流量可从本机架的 follower 走,省跨机房带宽;注意就近读的数据可能略落后于 leader(可见性权衡)。
这张时间线表是 ISR 机制的标准推演题。重点是 t2:A 宕机时 m11 丢没丢?没丢,因为 acks=all 的承诺对象是提交时刻的 ISR,m11 提交时 ISR 是 A 和 B,B 上有。C 掉队期间的写入本来就不等 C。t3 回归路径:先截断对齐再全量补齐,注意 C 上 m10 的残差是未提交数据,截掉是安全的。关键判定记一句:ISR 收缩不会让已可见数据回退,HW 只进不退。KIP-392 机架就近拉取一句话带过:client.rack 匹配 broker.rack,跨机房省带宽。
LEO / HW
两个水位定一致性:LEO 是末端,HW 是可见边界
LEO 和 HW 是一切一致性讨论的坐标系。LEO 是每副本日志的下一条写入位置,HW 是 leader 按 ISR 最小 LEO 裁决的可见边界。图里三个数字:B1 十一条、B2 十条、B3 八条,HW 等于八,消费者只能读零到七。第八九条已在 leader 和 B2 上但没过 HW,属于未提交段——它会随着 B3 追平变提交,也可能随掉队消失,但 acks=all 下它从没 ack 给生产者,所以不算丢。最后一句是引子:HW 的传播是异步的、滞后的,这个滞后就是后面两个经典缺陷的根源。
HW Defect #1 · Data Loss
问题一:HW 之下的"已 ack"消息会随 leader 一起消失
这是 KIP-101 讨论里的原始数据丢失场景,要能按格子讲。t1 是关键:m2 写入 leader 且 acks=1 已经回执,但还没复制到 B,此时 m2 只存在于即将出事的 A 上。t2 B 重启,旧规则按本地 HW 截断,这个动作本身没问题。t3 A 宕机,controller 合法地把 B 选为新 leader——注意这不是 unclean 选举。t4 B 日志里只有 m1,m2 永久消失,而它是 ack 过的。根因一句话:截断依据和 leader 真实日志不同步。解法两层:业务层 acks=all 加 min.insync 等于二,协议层就是 KIP-101。
HW Defect #2 · Inconsistency
问题二:老 leader 复活后的日志错位——不一致与重复
| 时刻 | 事件 | A 的日志 / 本地 HW | B 的日志 / 本地 HW |
| t0 | A 为 leader;m1 已提交(HW=1),m2 已写入 A 但未提交(LEO=2) | [m1, m2] · HW=1 | [m1] · HW=1 |
| t1 | A 短暂失联(GC/网络),controller 切主到 B;producer 未再写入 | 失联中 | [m1] · HW=1(成为 leader) |
| t2 | A 恢复:按旧机制先截断至本地 HW=1 → m2 被截掉 | [m1](m2 丢失) | [m1] |
| t3 | 变体①:A 以 follower 重新拉取——行为正常;变体②:老机制 + sticky leader 场景下 A 可能被再次选回,而它的日志已被截短 | 分叉风险 | — |
不一致怎么发生
截断发生在"重新加入"时,但本地 HW 是滞后的快照:若 A 的本地 HW 记录偏小、或 A 被再次选主,不同副本会以不同位置为"真相"——消费者在切换前后可能读到不同内容的同一位移(脏读),或已读消息重新出现(重复)。
与问题一的区别(答题加分点)
问题一丢的是已 ack 的数据(acks=1 场景);问题二是已提交数据的一致性视图被破坏——即使 acks=all,HW 的异步传播仍可能让截断决策与当期 leader 脱节。共同根源:HW 是滞后的、异步传播的截断依据。
面试一句话:"HW 机制的两个缺陷同根:用'滞后的全局水位'指导'本地的截断决策'。前者表现为已 ack 数据丢失(快故障),后者表现为副本间日志错位与消费视图不一致(慢故障)——KIP-101 用 LeaderEpoch 把截断决策改成'向当期 leader 问边界'来一并解决。"
问题二比问题一更绕,抓住时间线:A 是 leader,m1 已提交 m2 未提交;A 短暂失联切主到 B;A 恢复后按本地 HW 截断,m2 被截掉;麻烦在变体:老机制加 sticky leader 选举可能把 A 再选回去,而它的日志已经被截短了——不同副本以不同位置为真相,消费者可能读到不同内容的同一位移,这就是不一致和重复。和问题一的区别要主动说:问题一丢已 ack 数据,问题二破坏已提交数据的一致性视图,根源相同——滞后的水位指导本地截断。这句总结完直接引出 KIP-101。
KIP-101 · LeaderEpoch(0.11+)
KIP-101:把"盲截 HW"改成"向 leader 问 epoch 边界"
KIP-101 的精髓一句话:把截断决策从"查本地滞后的水位"改成"问当期 leader 要确定的边界"。流程四步:重启带 epoch 查询、发 OffsetsForLeaderEpoch、leader 返回该 epoch 的末端 offset、只截到这个点。为什么能同时解决两个问题:第一,截断点是当期 leader 数据的确定边界,已 ack 的数据不可能被截掉;第二,每次截断都先校验,盲截和错位不存在了。结构上记 LeaderEpochCache:epoch 到起始 offset 的映射随日志持久化,消息批头自带 partitionLeaderEpoch,整条日志就是带版本标记的历史。
Truncation · Cross-DB View
日志截断的三个场景,以及与 MySQL 主从复制的对照
| 截断场景 | 触发与规则 | 安全边界 |
| ① follower 恢复截断 | 重启/长时间掉队后重新加入:先向 leader 校验 LeaderEpoch 末端 → 截到确定边界 → 续拉 | 只截未提交段(校验后);已提交数据不动 |
| ② 选举后对齐截断 | 新 leader 日志可能短于旧 follower(旧 leader 未截断的未提交段):原 ISR 成员以新 leader 为准截齐 | 截掉的均为未过 HW 的未提交数据 |
| ③ unclean 选举后全量重同步 | 开启 unclean 后新 leader 可能远落后:存留副本需大幅截断 | 会出现已提交数据丢失(见下页) |
| 概念 | Kafka | MySQL 主从(对照记忆) |
| 复制坐标 | offset + LeaderEpoch(epoch 起始 offset 表) | binlog (file, pos) / GTID 集合——GTID 同样是"复制身份"思想 |
| 截断规则 | 以当期 leader 日志为准(epoch 校验) | 从库重做/回滚对齐主库;GTID 自动跳过已执行事务 |
| 掉队判定 | replica.lag.time.max.ms=30s 收缩 ISR | Seconds_Behind_Master 监控(无自动剔除) |
| 提交门禁 | acks=all + min.insync.replicas | 半同步复制 rpl_semi_sync_master_wait_for_slave_count |
跨 deck 串联:"Kafka 的 ISR+LeaderEpoch 与 MySQL 的主从+GTID 是同一组问题(复制坐标、截断、掉队、提交门禁)的两套实现——面试被问差异时按这张表的行逐一对照。"(半同步与 binlog 提交侧详见
MySQL 事务 deck)
截断场景收拢成三种:follower 恢复、选举后对齐、unclean 后全量重同步,前两种只动未提交段,第三种会丢已提交数据,这个安全边界是判断一切复制异常的标尺。下半张表是和 MySQL 主从复制的对照:GTID 和 LeaderEpoch 都是复制身份思想,semi-sync 和 acks 加 min.insync 都是提交门禁。面试被问跨系统差异就按行对照,这张表也是和相关 deck 串联的桥。
Unclean Leader Election
unclean.leader.election.enable:C 与 A 的总开关
false(默认,4.3 源码核实)
选举只允许从 ISR 成员中挑。ISR 全部不可用时:分区不可读不可写(新 leader 选不出),直到任一 ISR 副本恢复——宁肯停服,不丢已提交数据。金融/订单类链路的正确选择。
true
ISR 全挂时允许非 ISR 副本(OSR)上位:它的日志落后,上位即发生截断 → 已提交(已 ack 给生产者)的消息可能永久丢失。换取分区立即可用——日志类、可从上游重放的数据可以接受。
| 追问 | 答案 |
| 默认 false 时"副本全挂"到底什么现象? | produce 全部失败(超时/重试耗尽),consume 不可用;客户端视角是可用性事故而非数据事故——恢复后从 ISR 副本继续,数据零丢失 |
| 和 min.insync.replicas 什么关系? | 两层独立的门:min.insync 管"ISR 够不够资格收写"(写入可用性),unclean 管"非 ISR 能不能当 leader"(故障切换语义)。都不开 → 一致性最强、可用性最弱 |
| 运维建议? | 默认保持 false;确要开启按 topic 粒度(broker 默认值 + topic 覆盖)只对可容忍丢失的 topic 打开,并配监控告警"ISR 收缩到 1"提前介入 |
答题模板:"这是 CAP 里 C 与 A 的显式交换:unclean=false 保 C(可能不可用),true 保 A(可能丢已提交消息)。Kafka 把选择权交给 per-topic 配置,默认 false——先保证不骗人(不丢 ack 过的数据),可用性靠 ISR 健康度和容量规划来保。"
unclean 选举是 CAP 取舍的显式开关。默认 false:只能从 ISR 里选 leader,ISR 全挂就停服,宁可不可用不丢已提交数据。true:OSR 副本可以上位,日志落后上位即截断,已 ack 的消息可能永久丢。两个追问:默认 false 时全挂的现象是可写不可读的可用性事故,恢复后数据零丢;它和 min.insync 是两层独立的门,一个管写入资格一个管选举资格。运维建议:保持 false,确要开按 topic 粒度只开可容忍的,再配 ISR 收缩告警提前介入。
acks=all × min.insync.replicas × ISR
为什么 acks=all 仍可能丢:承诺对象是"当时的 ISR"
| acks | min.insync.replicas | 当前 ISR 数 | 结果 | 解读 |
| all | 2 | 3 | ✓ 正常:等 ISR 全部落盘(含 leader) | 提交即冗余 3 份 |
| all | 2 | 2 | ✓ 正常(贴线运行) | 再掉一台 → 见下一行 |
| all | 2 | 1 | 拒写 NotEnoughReplicas | 可用性换一致性:宁可停写不降级提交 |
| all | 1 | 1 | 退化为 acks=1:leader 落盘即 ack | 高频考点:all 只等 ISR——ISR 收缩到 1 时承诺消失,单点故障即丢 |
| 1 | 任意 | ≥1 | leader 落盘即回执 | 未及复制即宕机 → 丢(第 5 页场景) |
| 0 | — | — | 发出即成功 | 不重试不保证;乱序也可能 |
两个异常别混淆
NotEnoughReplicasException:append 前发现 ISR < min.insync → 拒收(日志无此消息),producer 重试直至超时;NotEnoughReplicasAfterAppendException:append 后 ISR 掉到门禁之下 → 消息在 leader 保留但不推进 HW/不 ack,等 ISR 恢复或重试超时。两者都是可重试异常。
生产组合拳(推荐基线)
topic:replication.factor=3 + min.insync.replicas=2;producer:acks=all(默认)+ enable.idempotence=true(默认)+ 回调兜底;broker:unclean.leader.election.enable=false(默认)。丢消息四查:acks 配置 → min.insync → unclean → 客户端是否处理回调异常。
标准答案句:"acks=all 的语义是'等 ISR 全部'而不是'等全部副本'——所以它防的是 ISR 内的丢失;ISR 本身收缩到 1 时的承诺真空,靠 min.insync.replicas 拒写来堵,这就是两者必须成对配置的原因。"
这页是"acks=all 为什么还丢"的完整答案。核心一句:all 只等 ISR 不等 AR。矩阵里最重要的一行是第四行:min.insync 配一、ISR 收缩到一,all 退化成 acks=1,单点故障即丢——这就是为什么 min.insync 必须显式调成二,默认值一等于没设防。两个异常的区分:append 前拒收和 append 后不推进 HW,都是可重试异常。最后给生产基线四件套:RF3、min.insync 二、unclean 关、幂等开,加上丢消息四查的排查顺序。
KRaft · Why
为什么移除 ZooKeeper:三宗罪与一次自我救赎
① 元数据双系统
集群真相存在 ZK,controller 要与 ZK 双向同步——两套一致性系统并存:ZK 仲裁 + Kafka 自身 ISR。controller 切换需从 ZK 重读全量元数据,故障切换慢且存在不一致窗口(元数据缓存与 ZK 不同步的脑裂风险)。
② 扩容瓶颈
ZK 的 znode 写入与 watch 通知吞吐限制了分区规模:每次分区状态变更、leader 切换都要写 ZK 并广播。KIP-500 的目标就是把元数据做成 Kafka 自己的 Raft 日志,支撑百万级分区。
③ 运维复杂
两套系统两套部署/监控/权限/安全模型:ZK 集群本身要维护、升级、扩容;跨系统故障排查(ZK 会话过期 vs broker 心跳)认知负担重。KRaft 后一个集群一套软件。
| 追问 | 答案 |
| KRaft 的核心思路一句话? | 元数据也是日志:把集群元数据(broker 注册、topic/分区/配置、ISR 变更)做成内部 Raft 日志主题 __cluster_metadata,由 controller quorum 用 Kafka 自己的 Raft 实现(KIP-595)复制 |
| ZK 时代 controller 怎么选主?KRaft 后呢? | ZK 时代靠 ZK 的临时节点/锁选 controller(单点活跃,切换慢);KRaft 后 controller quorum 内部跑 Raft 选主——复用与数据面同源的共识机制,秒级且更稳 |
| 移除 ZK 对已有用户意味着什么? | 4.0 起 ZK 模式代码整体移除(不是弃用):升级必须先迁 KRaft(zk2kraft 迁移路径);配置体系同步清理(zookeeper.connect 等退出历史舞台) |
为什么移除 ZooKeeper 归纳为三宗罪:元数据双系统,两套一致性并存,controller 切换要重读 ZK,慢且有不一致窗口;扩容瓶颈,ZK 写吞吐限制分区规模,KIP-500 的目标就是百万级分区;运维复杂,两套部署监控权限。KRaft 的核心思路一句话就能立住:元数据也是日志,存进 __cluster_metadata 由 controller quorum 用 Raft 复制。选主对比也是常问点:ZK 时代靠临时节点锁,KRaft 后 quorum 内部跑 Raft 选主。版本口径:4.0 是整体移除不是弃用,升级必须先迁。
KRaft · Architecture
KRaft 架构:Controller Quorum + __cluster_metadata + 演进线
KRaft 架构看三层。上层 controller quorum,三或五个奇数节点跑 Kafka 自己的 Raft,active controller 处理元数据写入,多数派落盘到 __cluster_metadata 才算生效——注意这是真正的多数派,和数据面 ISR 是两套机制。中层 broker 用快照加增量 fetch 把元数据同步成本地 MetadataCache,数据面协议基本没变。底部时间线背四个点:2.8 预览、3.3 production ready、4.0 彻底移除 ZK、4.3 现行。追问点:小集群可以 combined 模式让 controller 和 broker 同进程,生产大集群建议分离部署。
Interview QA · 1/2
ISR 与一致性 8 连问
1 · ISR 是什么?怎么进入和退出?
动态副本集30s 追平窗口
in-sync replicas:与 leader 保持追平的副本集合(含 leader)。退出:30s(replica.lag.time.max.ms)内没发 fetch 或没追到日志末端 → 移出 OSR。回归:截断对齐 + 全量补齐 + 追平末端 → leader 自动拉回,无需重启。
2 · LEO 和 HW 是什么?消费者能读到什么?
LEO 末端HW 可见边界
LEO=各副本日志下一条写入位置;HW=leader 按 min(ISR LEO) 裁决的可见边界,随 fetch 响应异步广播。消费者只读 < HW——永远看不到可能随宕机消失的未提交数据。
3 · follower 什么时候被截断日志?
恢复/选举后对齐
两类正常场景:重启/掉队恢复时按 LeaderEpoch 校验截到确定边界;leader 切换后以新 leader 为准对齐(截掉的均为未过 HW 的未提交段)。unclean 选举后才有"截掉已提交数据"的例外。
4 · acks=all 为什么还可能丢消息?
只等 ISRISR 可收缩到 1
all 的承诺对象是"提交时刻的 ISR"而非全部副本:ISR 收缩到 1 时退化为 acks=1,leader 单点故障即丢。解法:min.insync.replicas=2 拒绝低冗余写入(NotEnoughReplicas)+ unclean=false + 幂等回调兜底。
5 · min.insync.replicas 与两个异常的区别?
写入门禁拒收 vs 不提交
它是 broker 端写入门禁:ISR 数不足则拒。NotEnoughReplicasException=append 前拒收(消息没进日志);NotEnoughReplicasAfterAppendException=append 后 ISR 掉线,消息保留但不推进 HW 不 ack。两者均可重试。
6 · unclean.leader.election.enable 默认值与权衡?
false(默认)C 换 A
默认 false(4.3 源码):只从 ISR 选 leader,ISR 全挂则分区不可用但已提交数据零丢;true 允许 OSR 上位,可能丢已 ack 消息,换取立即可用。按 topic 粒度对可容忍丢失的数据开启。
7 · Kafka 复制为什么不用多数派写?
f+1 容 f省一半副本
ISR 模型 f+1 副本容 f 故障(多数派需 2f+1):2 副本容 1 台宕机,磁盘与写放大省一半。代价:acks=all 的提交延迟受最慢 ISR 成员影响(多数派只等最快过半)。可用性靠 min.insync 门禁与 unclean 开关显式取舍。
8 · 副本全挂了会怎样?
不可用 vs 丢数据
unclean=false(默认):分区不可读不可写,客户端超时/重试失败——可用性事故但数据安全,任一 ISR 副本恢复即服务恢复;unclean=true:OSR 上位立即恢复服务,但截断导致已提交消息丢失。先监控 ISR 收缩,别等到全挂。
上半场八题覆盖 ISR 主干。第二题两句话定义 LEO 和 HW,加上异步传播这个性质。第四题是核心考点:all 只等当时的 ISR,ISR 收缩到一就退化,答案落在 min.insync 等于二加 unclean 关闭。第五题两个异常要分清拒收和不提交。第七题说明白为什么不用多数派:f 加一容 f 省一半副本,代价是提交延迟受最慢成员拖累。第八题把全挂现象说成"可用性事故而非数据事故",这句话能体现对默认值设计的理解。
Interview QA · 2/2
HW 缺陷、KIP-101 与 KRaft 8 连问
9 · HW 机制有哪两个经典缺陷?
数据丢失日志错位
① 快故障:acks=1 下已 ack 的消息只存在于 leader,follower 截断后 leader 宕机 → 该消息永久丢失;② 慢故障:本地 HW 滞后导致多截、老 leader 复活错位 → 副本日志分叉、消费视图不一致/重复。共同根源:滞后的水位指导本地截断决策。
10 · KIP-101 怎么修复的?
LeaderEpochOffsetsForLeaderEpoch
日志带 partitionLeaderEpoch;follower 截断前发 OffsetsForLeaderEpoch(当前 epoch),leader 返回该 epoch 的末端 offset → 只截到确定边界再续拉。同 epoch 内与 leader 严格一致:① 已 ack 数据不再被截 ② 盲截与错位消失(0.11+ 实现)。
11 · LeaderEpoch 的数据结构?
epoch→startOffset随日志持久化
LeaderEpochCache 维护 [(epoch, startOffset)] 向量,如 [(0,0),(1,20),(2,55)],checkpoint 文件随日志持久化;每条消息批头携带 partitionLeaderEpoch。选举成功即 epoch+1——"任"是复制协议的一致性分界。
12 · 与 MySQL 主从复制对照?
GTID ↔ LeaderEpochsemi-sync ↔ acks 门禁
复制坐标:binlog(GTID) ↔ offset+epoch;掉队处理:Seconds_Behind 监控 ↔ 30s 收缩 ISR;提交门禁:semi-sync 副本数 ↔ acks=all+min.insync;截断:GTID 跳过已执行 ↔ epoch 校验截断。同一组问题两套实现。
13 · 为什么移除 ZooKeeper?
双系统扩容瓶颈运维复杂
① 元数据真相在 ZK:双一致性系统、controller 切换慢且有不一致窗口;② ZK 写吞吐限制分区规模(KIP-500 目标百万分区);③ 两套部署/监控/权限的认知负担。KRaft 把元数据做成自己的 Raft 日志,一套软件闭环。
14 · KRaft 的架构要点?
Controller Quorum__cluster_metadata
3/5 个奇数 controller 组成 Raft 仲裁(KIP-595 协议),active controller 处理元数据写入,多数派落盘 __cluster_metadata(单分区元数据日志);broker 通过快照+增量 fetch 维护本地 MetadataCache;数据面 produce/fetch 协议与 ZK 时代基本一致。
15 · KRaft 的版本演进口径?
3.3 production ready4.0 移除 ZK
2.8 KIP-500 预览(early access);3.3 KIP-833 标记 production ready;4.0(2025-03)成为首个无 ZooKeeper 的大版本——ZK 模式代码整体移除,升级必须先迁 KRaft(zk2kraft)。4.3 为现行版本,KRaft 是唯一模式。
16 · KIP-392 follower fetching 是什么?
机架就近读2.4+
消费者/ follower 配置 client.rack,broker 按 broker.rack 把 fetch 路由到本机架的副本 follower——跨机房部署省跨区带宽与延迟。注意就近读可见性略滞后于 leader;默认不开启(默认读 leader)。
下半场八题。第九第十连着答:两个缺陷同根同源,KIP-101 四步流程要能脱稿讲,OffsetsForLeaderEpoch 这个 API 名要报得出来。第十一题报结构:epoch 加 startOffset 的 checkpoint 文件,批头带 partitionLeaderEpoch。第十二题 MySQL 对照是跨领域加分题。第十三到十五是 KRaft 三连:为什么移除、架构要点、版本演进口径,三个版本号必须准确。第十六题 KIP-392 一句话收尾:机架就近读省跨机房带宽,默认不开。
Related Decks
相关知识点与答题串联
答题串联 · 一图流
ISR 动态集合(30s 窗口)→ LEO/HW 水位
HW 截断 → 丢失(快)/错位(慢)两缺陷
KIP-101 → OffsetsForLeaderEpoch 校验截断
acks=all × min.insync × ISR → 拒写矩阵
元数据一致性 → KRaft(3.3 ready → 4.0 去 ZK)
收尾第一页给同领域链接与答题串联主线:ISR 水位、两个缺陷、KIP-101、acks 矩阵、KRaft——五行走完,这条 deck 的骨架就复现了。四条链接各对应一次跨 deck 复习:写路径、客户端语义、消费可见性、MySQL 对照。
References
参考来源
| kafka.apache.org/documentation(#design · #datacenters · #configuration) | 复制设计、ISR 语义、acks/min.insync/unclean 配置说明 |
| github.com/apache/kafka(4.3)server/.../config/ReplicationConfigs.java · storage/.../LogConfig.java · server-common/.../ServerLogConfigs.java | 源码级默认值核实:replica.lag.time.max.ms=30000 · unclean.leader.election.enable=false · min.insync.replicas=1 |
| cwiki.apache.org/confluence/display/KAFKA/KIP-101(Alter Replication Protocol to use Leader Epoch rather than High Watermark for Log Truncation) | 两个 HW 缺陷的原始推演与 LeaderEpoch 方案(lists.apache.org 讨论线程同源) |
| cwiki.apache.org/confluence/display/KAFKA/KIP-392(Allow consumers to fetch from closest replica) | 机架就近拉取(client.rack/broker.rack,2.4+) |
| KIP-500 / KIP-595 / KIP-631 / KIP-833(cwiki.apache.org/confluence/display/KAFKA/) | KRaft:元数据 quorum 提案、Kafka Raft 协议、quorum-based controller、3.3 production ready |
| kafka.apache.org/blog/2025/03/18/apache-kafka-4.0.0-release-announcement/ | 4.0 发布公告:首个完全移除 ZooKeeper 的大版本(KRaft-only) |
最值得原文精读:KIP-101——两个 HW 缺陷的原始推演就写在它的讨论线程里。
键盘操作:←→ 翻页 · T 换主题 · S 演讲者模式 · O 总览。
溯源清单页。最值得精读的是 KIP-101 原文——两个缺陷的原始推演就写在讨论线程里,以及 4.3 源码的三个默认值(30s 追平窗口、unclean 默认 false、min.insync 默认 1)。所有版本敏感结论都标了出处,被深挖时直接报材料。