介绍一下 Kafka 的 ISR 机制?
结论:ISR(In-Sync Replicas)是与 Leader 保持同步的副本集合,包含 Leader 本身。判断标准是 Follower 的拉取进度落后 Leader 不超过
replica.lag.time.max.ms(默认 30 秒)。ISR 有两个作用:决定acks=all要等哪些副本,决定 Leader 挂掉后谁能接任。ISR 越短,可靠性越低。
一、ISR 的动态维护
Leader(LEO=1200, HW=1100) ISR = [L, F1, F2]
│ F1 拉取到 1150,F2 只到 800
▼
┌─────────────────────────────────────────────┐
│ F2 落后 400 条,且超过 30s 没追上 │
│ → Controller 把 F2 踢出 ISR │
│ → ISR = [L, F1],F2 进入 OSR(普通副本) │
└─────────────────────────────────────────────┘
│ F2 恢复,持续追到 LEO 附近
▼
F2 重新加入 ISR,HW 恢复推进
| 参数 | 默认值 | 作用 |
|---|---|---|
replica.lag.time.max.ms | 30000 | Follower 超过该时长未追上 Leader 则移出 ISR |
replica.fetch.max.bytes | 1MB | 单次拉取上限,过小会导致大消息同步慢 |
num.replica.fetchers | 1 | Follower 拉取线程数,跨机房/高延迟时可调大 |
min.insync.replicas | 1 | 写入时要求的最小 ISR 数量,低于此值 acks=all 抛异常 |
acks | all | 生产端等待 ISR 全部确认 |
历史上还有过按消息条数判断的 replica.lag.max.messages,因为大流量下误判严重已被移除,现在只看"时间"。
二、LEO 与 HW 的推进
| 概念 | 含义 | 谁维护 |
|---|---|---|
| LEO(Log End Offset) | 副本下一条待写入消息的位移 | 每个副本各自维护 |
| HW(High Watermark) | ISR 中最小的 LEO,消费者可见的上界 | Leader 维护并随 Fetch 响应下发 |
| LSO(Last Stable Offset) | 未完成事务之前的位移,read_committed 消费者可见的上界 | Leader 维护 |
Follower 发出 FetchRequest(fetchOffset=LEO),Leader 返回数据后 Follower 追加写、推进自己的 LEO,并在下一次 Fetch 中上报;Leader 收到后更新 HW = min(ISR 各副本 LEO),再把 HW 带回响应。HW 的推进至少要一次额外的 Fetch 往返,这就是"副本都写完了但消费者暂时读不到"的原因。
三、ISR 与写入可用性
# Broker
replica.lag.time.max.ms=30000
min.insync.replicas=2
unclean.leader.election.enable=false
# 生产端
acks=all
组合效果:
- ISR = 3,写入等 3 个副本确认,最稳最慢;
- ISR 缩到 2,仍满足
min.insync.replicas=2,写入继续但容错降为 0; - ISR 缩到 1,低于下限,生产端收到
NotEnoughReplicasException,这是保护而不是故障; - 若
min.insync.replicas=1,ISR 只剩 Leader 时acks=all退化成acks=1,看似成功实则单副本。
四、观察与排查
# ISR 列就是当前同步副本集合,副本前的数字是 Leader
kafka-topics.sh --bootstrap-server 10.0.0.31:9092 --describe --topic order-events
# 检查副本之间是否有数据落后
kafka-replica-verification.sh --broker-list 10.0.0.31:9092 \
--topic-white-list 'order-events'
如果 ISR 频繁收缩,按顺序排查:Follower 所在磁盘 IO 是否打满 → 网络是否抖动 → num.replica.fetchers 是否太小 → 是否单条消息超过 replica.fetch.max.bytes 导致同步卡住。
五、常见追问
- ISR 包含 Leader 吗? 包含。所以"ISR=1"意味着只剩 Leader,而不是"没有副本"。
- Follower 落后一点就被踢,会不会太敏感? 判据是"30 秒内是否追上过",短暂抖动不会触发;一旦持续落后,继续留在 ISR 反而会拖慢 HW 推进并增加丢数据风险。
- ISR 收缩会丢消息吗? 不会直接丢,但缩小了
acks=all的等待范围,故障时抗风险能力下降。 - KRaft 下 ISR 由谁管? 由 Controller 统一管理并写入元数据日志,不再依赖 ZooKeeper 节点,变更传播更快。
小结
- ISR = 与 Leader 同步的副本集合(含 Leader),按时间判据动态进出。
acks=all等的是 ISR,min.insync.replicas是 ISR 的下限保护。- HW = ISR 最小 LEO,决定消费者能读到哪;HW 推进依赖额外的 Fetch 往返。
- ISR 频繁抖动是磁盘、网络或拉取线程不足的信号,必须查根因而不是调大超时。