kafka Epoch机制
一、Controller Epoch(控制器任期)
1. 作用
2. 原理
全局唯一,初始为 0,每次 Controller 选举成功 + 1。
存于 ZK
/controller_epoch,写操作必须携带当前 Epoch。脑裂时:多个节点抢 Controller,Epoch 最大者获胜;旧 Controller(Epoch 更小)发的请求被忽略。
3. 示例
节点A成为Controller → Epoch=1 节点A宕机,节点B当选 → Epoch=2 节点A恢复,试图发指令(带Epoch=1)→ 集群拒绝(当前Epoch=2)
二、Leader Epoch(分区 Leader 任期,0.11.0 + 引入)
1. 背景:旧版 HW 机制的缺陷
HW(高水位):所有 ISR 副本都已同步的最大 Offset,代表 “已提交、对消费者可见” 的位置。
问题:Follower 的 HW 更新滞后一轮拉取,主从 HW 不一致;切换 Leader 时可能误截断已提交数据,导致丢失 / 不一致。
2. 核心定义(每个分区独立)
Epoch:单调递增,每次分区 Leader 切换 + 1(Leader 的 “世代号”)。
StartOffset:当前 Epoch 下,新 Leader 写入的第一条消息的 Offset。
每个 Broker 维护:Leader Epoch Map(Epoch → StartOffset),内存缓存 + 磁盘 checkpoint 文件持久化。

3. 工作流程(故障切换 + 恢复)
初始状态:Partition P,Leader=A,Epoch=0,StartOffset=0;日志到 Offset=100,HW=90。
切换 Leader:A 宕机,B 当选新 Leader → Epoch=1,StartOffset=100;新消息从 100 开始写。
旧 Leader 恢复:A 重新连集群,携带自己的最新 Epoch=0。
数据对齐:
B(Epoch=1)对比 A 的 Epoch:0 < 1 → A 的日志过时。
B 告诉 A:截断到 Epoch=1 的 StartOffset=100,再从 B 拉取 100 之后的数据。
结果:A 被 “矫正”,不会误删已提交数据,避免不一致。
4. 解决的关键问题
防止数据丢失:旧版可能把 HW=90 之后(已提交)的消息删掉;Epoch 保证只截未提交的 “无效数据”。
加速副本同步:Follower 无需全量对比日志,按 Epoch 快速定位截断点。
幂等 / 事务基础:每条消息携带当前 Leader Epoch,跨 Leader 的消息顺序与提交状态可追溯。
三、两类 Epoch 对比
| 类型 | 作用域 | 递增时机 | 核心目的 |
|---|---|---|---|
| Controller Epoch | 整个集群 | 每次 Controller 选举 | 防脑裂,保证单 Controller 有效 |
| Leader Epoch | 单个 Partition | 每次分区 Leader 切换 | 防数据丢失 / 不一致,加速同步 |
四、核心配置与查看
1. 查看 Leader Epoch(Shell)
# 进入Kafka Shellbin/kafka-console.sh# 查看分区详情(含Leader Epoch)describe topic test_topic --partitions 0
2. 相关配置(server.properties)
# 开启Leader Epoch(默认true)leader.epoch.checkpoint.enable=true# checkpoint文件路径log.dirs=/kafka/logs
五、总结
Epoch 本质是 “版本号”:Controller Epoch 管集群,Leader Epoch 管分区。
Leader Epoch 是数据一致性的关键:0.11 后替代旧 HW 截断逻辑,彻底解决切换时的数据丢失。
一句话:有了 Epoch,Kafka 在任何故障切换后,都能精准判断 “哪些数据该留、哪些该删”。


