精选·Kafka与消息队列

Kafka 整体架构是怎样的?ISR 机制解决了什么问题?

91学AI·2026/7/13·10 阅读

考察点

这是 Kafka 的开门题,面试官想确认你不是只会调 API,而是理解集群内部怎么运转。核心看三点:角色分工(Broker、Controller、ZooKeeper/KRaft)、副本复制模型(Leader/Follower 拉模式)、ISR 的权衡思想。答得好会往 HW/LEO、Unclean Leader Election、acks 配置上追问,这题本质上是后面所有可靠性问题的地基。

参考答案

整体架构:几个角色先摆清楚

一个 Kafka 集群由多个 Broker 组成,Topic 是逻辑概念,真正的存储和并行单位是 Partition。每个 Partition 有多个副本(Replica),分布在不同 Broker 上,其中一个副本是 Leader,负责所有读写;其余是 Follower,只做一件事:向 Leader 发 Fetch 请求同步数据。注意 Follower 不对外服务,这一点和 MySQL 主从、Redis 主从读写分离不一样,面试时经常有人在这里说错。

集群里有一个特殊 Broker 叫 Controller,由集群内部选举产生(老版本借助 ZooKeeper,2.8 之后有 KRaft 模式去 ZK 化,3.x 已成主流方向)。Controller 负责分区 Leader 选举、副本分配、Broker 上下线时的元数据变更。普通 Broker 只存数据,Controller 管"谁在哪当 Leader"这本账。

Producer 只往 Leader 写,Consumer 只从 Leader 读(新版本支持从就近副本读以跨机房省流量,但默认仍是 Leader)。元信息(哪个分区的 Leader 在哪个 Broker 上)由客户端首次连接时拉取并缓存,路由错了会被 Broker 纠正后刷新。

复制模型与 ISR

Kafka 的复制是拉模式:Follower 主动 fetch Leader。那么问题来了——Follower 那么多,有的同步快有的慢,Producer 写一条消息,算"提交成功"需要等几个副本确认?全等,慢节点拖死集群;不等,Leader 挂了丢数据。

Kafka 的答案是 ISR(In-Sync Replicas):动态维护一个"跟得上 Leader"的副本集合,Leader 自己永远在 ISR 里。Follower 如果在 replica.lag.time.max.ms(默认 30 秒)内没有落后 Leader 太多(旧版本还看消息条数 lag,后来改成只看时间),就留在 ISR;持续跟不上就被踢出去,追上后再加回来。这个集合由 Leader 记录并同步到元数据里。

提交(committed)的定义是:消息被 ISR 里所有副本都写入。所以 acks=all 时,Producer 等的是 ISR 全员确认,而不是全部副本。一个慢 Follower 被踢出 ISR 后就不再阻塞写入——这就是 ISR 的精髓:用动态成员机制把"等几个副本"从固定数字变成"等当前健康的那批",在可靠性和可用性之间取得平衡

HW 与 LEO:消费者能看到哪条消息

每个副本有两个水位:LEO(Log End Offset),下一条要写入的位置;HW(High Watermark),已提交消息的最高位移,消费者只能读到 HW 之前的消息。Leader 的 HW 由 ISR 里最小的 LEO 决定。

举个例子:Leader 的 LEO 是 10,ISR 里两个 Follower 的 LEO 分别是 8 和 9,那 HW 就是 8。Follower 每次 fetch 的响应里会带回 Leader 当前的 HW,Follower 把自己的 HW 更新为 min(Leader HW, 自己的 LEO)。

这里顺带分清两个容易混的概念:AR(Assigned Replicas)是分区创建时分配的全部副本,固定不变(除非重分配);ISR 是 AR 里当前跟得上的子集,动态伸缩。常说的"副本因子 3"指的是 AR 是 3,而 acks=all 等的只是 ISR,两者之间的差集就是那些掉队但还挂着名的副本。

这套机制配合 Leader Epoch(每次 Leader 换届 epoch 加一,记录每个 epoch 的起始位移)解决了旧版本单纯靠 HW 做截断可能出现的数据不一致问题——新 Leader 上任后,Follower 按 Leader Epoch 的 checkpoint 截断掉未提交的脏数据。

Leader 挂掉之后

Controller 探测到 Leader 所在 Broker 失联后,从 ISR 里挑一个副本当新 Leader。因为 ISR 成员都持有了全部已提交消息,所以已提交的数据不丢。这里有个开关 unclean.leader.election.enable:设为 true 时,ISR 全挂了也允许从非 ISR 副本里选 Leader,可用性优先但会丢已提交数据,金融类业务千万别开。

可能的追问

  • 为什么不学 MySQL 做主从读写分离,让 Follower 也分担读? 副本同步有延迟,从 Follower 读会读到旧数据,Kafka 选择用分区水平扩展来扛读压力,语义更简单。新版本支持 follower fetching 是为了跨机房省流量,不是为了一致性读。
  • ISR 缩到只剩 Leader 自己,acks=all 还有意义吗? 有,此时退化为"Leader 写完就算提交",Leader 一挂数据就丢。所以要配 min.insync.replicas=2,ISR 不足 2 时直接拒绝写入。
  • KRaft 和 ZooKeeper 模式差在哪? 元数据从 ZK 挪进集群内部的 __metadata 主题,用 Raft 协议在 Controller 节点间复制。启动更快、分区上限更高、少一个外部依赖,但脑裂防护和运维工具链的成熟度是要评估的点。

评论 (0)

暂无评论,快来抢沙发吧!

91学AI

© 2026 91学AI · 按岗位学 AI 与大数据. All rights reserved.