ISR 与副本同步
定义与作用
ISR(In-Sync Replicas,同步副本集)是 Partition 副本中与 Leader 保持同步的副本集合。ISR 是 Kafka 可靠性的核心概念:只有 ISR 中的副本才有资格在 Leader 故障时成为新 Leader。
ISR 源于 Kafka 的实用主义设计——不强求所有 Follower 完全同步(网络延迟不可避免),而是允许"跟得上"的副本参与决策。
核心原理
ISR 维护机制
| 状态 | 条件 | 含义 |
|---|---|---|
| 在 ISR | replica.lag.time.max.ms 内有 Fetch 请求 | 副本活跃且跟得上 |
| 被踢出 ISR | 超过 replica.lag.time.max.ms 未 fetch 或落后太多 | 副本落后 |
| 重新加入 ISR | 追上 Leader 的 LEO | 恢复同步 |
ISR 收缩与扩展
关键参数
| 参数 | 默认值 | 说明 |
|---|---|---|
replica.lag.time.max.ms | 30000 (30s) | Follower 未 fetch 的最大容忍时间 |
replica.fetch.wait.max.ms | 500 | Follower 每次 fetch 的最大等待时间 |
min.insync.replicas | 1 | Producer 确认写入所需的最小 ISR 数量 |
replica.fetch.max.bytes | 1048576 (1MB) | 每次 fetch 的最大字节数 |
完整示例
示例一:观察 ISR 收缩
场景:3 Broker 集群,关闭一个 Broker 观察 ISR 变化。
操作前:
bin/kafka-topics.sh --describe --topic demo --bootstrap-server localhost:9092
# Partition: 0 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
操作:关闭 Broker 3。
kill $(jps | grep "server3" | awk '{print $1}')
操作后(约 30 秒后):
bin/kafka-topics.sh --describe --topic demo --bootstrap-server localhost:9092
# Partition: 0 Leader: 1 Replicas: 1,2,3 Isr: 1,2
# → Broker 3 被踢出 ISR
恢复:重启 Broker 3 后:
bin/kafka-topics.sh --describe --topic demo --bootstrap-server localhost:9092
# Partition: 0 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
# → Broker 3 重新加入 ISR
示例二:min.insync.replicas 拒绝写入
场景:Topic 设置 min.insync.replicas=2,ISR 收缩到 1 个时验证写入被拒绝。
操作前:
# 设置 Topic 级别 min.insync.replicas
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type topics --entity-name demo-ack \
--alter --add-config min.insync.replicas=2
# 查看当前状态
bin/kafka-topics.sh --describe --topic demo-ack --bootstrap-server localhost:9092
# Partition: 0 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
操作:停止 Broker 2 和 Broker 3(ISR 只剩 Broker 1)。
# 尝试发送(acks=all)
bin/kafka-console-producer.sh --topic demo-ack \
--bootstrap-server localhost:9092 \
--producer-property acks=all
> hello world
结果:消息卡住,超时后报错:
NOT_ENOUGH_REPLICAS
原因:acks=all 要求所有 ISR 副本确认。但 min.insync.replicas=2,当前 ISR 只有 1 → 写入被拒绝。
易错场景
易错 1:ISR 频繁收缩/扩展("抖动")
场景:网络不稳定导致 Follower 偶尔延迟超过 30s。
后果:ISR 频繁变化 → 触发 Leader Epoch 变更 → Producer 出现 NOT_LEADER_FOR_PARTITION → 重试 → 重复消息。
解决:增大 replica.lag.time.max.ms(如 60s),减少网络抖动导致的误判。
易错 2:min.insync.replicas=1 + acks=all
场景:生产环境设置 min.insync.replicas=1 且 acks=all。
后果:min.insync.replicas=1 意味着只要 Leader 确认就 OK,acks=all 变成了 acks=1。如果 Leader 在确认后立即宕机且数据未被 Follower 同步 → 数据丢失。
规则:生产环境应确保 min.insync.replicas ≥ 2 且 < replication-factor。
面试高频考点
Q:一个 3 副本的 Kafka 集群,acks=all,min.insync.replicas=2,最多能容忍几台 Broker 宕机而不丢失数据?
A:
| 场景 | ISR | 是否可写入 | 是否丢数据 |
|---|---|---|---|
| 0 台宕机 | [1,2,3] | 是 | 否 |
| 1 台宕机 | [1,2] | 是(ISR=2 ≥ min.insync=2) | 否 |
| 2 台宕机 | [1] | 否(ISR=1 < min.insync=2) | 已写入的数据不丢,新写入拒绝 |
结论:最多容忍 1 台 Broker 宕机而不会拒绝写入。宕机 2 台时服务不可用(NOT_ENOUGH_REPLICAS),但已写入且确认的数据不丢失(因为至少 2 个副本已确认)。