Skip to content

概念卡片:Kafka架构与高可用

一句话机制:Kafka 高可用 = 分区多副本(1 Leader + N Follower)+ ISR 动态集合 + HW/LEO 水位同步 + Controller 统一管理;只有 Leader 对外服务,Follower 只做冗余同步,Leader 挂了从 ISR 中选新 Leader——不丢已提交消息的前提是副本同步赶得上(ISR 覆盖),且不允许未同步副本当选(unclean 关闭)

副本管理:AR / ISR / OSR

集合含义
AR(Assigned Replicas)分区全部副本的集合
ISR(In-Sync Replicas)与 Leader 保持同步的副本(含 Leader 自己),只有 ISR 成员有资格晋升 Leader
OSR(Out-of-Sync Replicas)落后过多的副本;AR = ISR + OSR
  • ISR 由 Leader 动态维护:Follower 落后超过 replica.lag.time.max.ms(默认 10s)→ 移入 OSR;追平 → 移回 ISR。
  • 早期还有落后条数维度 replica.lag.max.messages0.10.x 起只支持时间维度

HW 与 LEO:消费可见水位

概念含义
LEO(Log End Offset)分区下一条待写入消息的位移,ISR 每个副本各自维护
HW(High Watermark)ISR 中最小的 LEO;HW 之前的消息已同步、消费者可见,之后不可见

HW 更新流程:Follower 拉取数据更新自身 LEO → Leader 取所有 Follower 的最小 LEO 更新自己的 HW → 再把 HW 响应给 Follower 同步。HW 决定了消费者能看到哪一条

读写分离为什么不支持

  • 数据不一致:副本间同步必有延迟窗口。
  • 延时问题:读走 Follower 要多过一次「Leader 磁盘 → Follower 磁盘」的拷贝,对低延时应用不友好。
  • Kafka 靠主写主读 + 分区分布天然负载均衡:Leader 均匀分布在各 broker 上,读写压力自然分摊。

Controller 与优先副本

  • Controller:集群唯一,负责 Leader 选举、ISR 变化通知、分区重分配。选举靠 ZK 的 /controller 临时节点(谁建成功谁是);配合持久节点 controller_epoch(初始 1,每换届 +1),交互请求带 epoch,旧控制器的过期请求会被拒绝
  • 优先副本(preferred replica)= AR 中第一个副本。理想情况下 Leader 应落在优先副本上;Leader 切换后可能集中到少数 broker 造成负载不均,优先副本选举把 Leader 拉回原位均衡负载。

分区再分配(解决什么)

  • 场景:broker 下线后失效分区不会自动迁移(负载空转);新增 broker 时老分区不会搬过去(新旧不均)。
  • 原理:Controller 给分区新增副本 → 网络复制数据到新副本(可限流)→ 复制完成清除旧副本

分区放置与存储

  • 创建 Topic 时:副本因子 ≤ broker 数;P0 首副本随机选 broker,后续分区首副本依次顺移;其余副本由随机 nextReplicaShift 决定。
  • 存储:partition = 磁盘一个目录,内分 segment(默认 1G,超限滚动新段,以最后一条消息的 offset 命名);消息格式 = 消息长度(4B) + 版本号(1B) + CRC32(4B) + 消息体(nB)。
  • log.dirs 多目录时选分区目录最少的目录建新分区(不是磁盘余量最少)。

分区数不是越多越好

  1. 内存成本:服务端分区级缓存、消费线程数、生产者按分区缓存消息,分区越多开销越大。
  2. 文件句柄:每分区多个 segment 段,每段 index+log 两个句柄,易触 OS 句柄上限。
  3. 端到端延迟:副本复制线程少(默认每 broker 一个复制线程),分区多了复制积压。
  4. 高可用下降:故障恢复时 Controller 需从 ZK 逐个读分区元数据——1 万分区约 2ms/个,恢复多出约 20s 不可用窗口

不变量(必须成立的约束)

  • 只有 Leader 对外读写,Follower 只同步(与 MySQL 主从可读不同)。
  • 只有 ISR 副本能当选 Leader;HW = ISR 最小 LEO。
  • 消费者组内:一个分区同一时刻只被一个消费者消费
  • 负载均衡依赖分区均匀分布,无法保证绝对均衡(broker/生产/消费/Leader 切换四类不均)。

常见误解

  • 以为 Follower 可分担读流量 → Kafka 不支持读写分离,Follower 是纯冗余。
  • 以为 Controller 是特殊节点 → 它就是一个 broker,靠 ZK 临时节点竞选出来的角色。
  • 以为副本数越多越稳 → 副本多 = 同步慢 + 存储翻倍,且 factor 必须 > min.insync.replicas,否则挂一个副本分区就不可用。

关联

最近更新