主题
概念卡片: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.messages,0.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多目录时选分区目录最少的目录建新分区(不是磁盘余量最少)。
分区数不是越多越好
- 内存成本:服务端分区级缓存、消费线程数、生产者按分区缓存消息,分区越多开销越大。
- 文件句柄:每分区多个 segment 段,每段 index+log 两个句柄,易触 OS 句柄上限。
- 端到端延迟:副本复制线程少(默认每 broker 一个复制线程),分区多了复制积压。
- 高可用下降:故障恢复时 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,否则挂一个副本分区就不可用。
关联
- 总览:Kafka技术栈总览
- 可靠性:概念卡片:Kafka消息可靠性不丢不重
- 面试:面试题蒸馏卡:Kafka
- 协调底座:概念卡片:Zookeeper协调服务