---
title: Kafka 副本与消息可靠性（ISR + 消息不丢 + 100% 边界）
type: concept
domain: mq
tags: [kafka, reliability, isr, high-watermark, replication, acks, at-least-once]
status: learning
created: 2026-09-22
last_reviewed: 2026-09-22
method: feynman
related_questions:
  - "介绍一下 Kafka 的 ISR 机制？"
  - "Kafka 如何保证消息不丢失？"
  - "为什么 Kafka 没办法 100% 保证消息不丢失？"
related_knowledge:
  - ./kafka-partition-performance.md
  - ./kafka-transaction.md
visualizations: []
anki_cards: 8
interview_rounds:
  - "2026-09-22-round-2-Q6"
  - "2026-09-22-round-2-Q7"
  - "2026-09-22-round-2-Q9"
---

# Kafka 副本与消息可靠性（ISR + 消息不丢 + 100% 边界）

> ISR 是 Kafka 副本一致性协议的核心；消息可靠性靠"三段链路 + 关键参数"组合；Kafka 只能保证 At-Least-Once，不能保证 Exactly-Once。

## TL;DR（30 秒扫完）

- **副本三层**：AR（静态所有副本）→ ISR（跟上 Leader 的动态子集）→ OBR（落后被踢的副本）
- **HW（High Watermark）** = min(所有 ISR 副本 LEO)，消费者只能读 HW 之前的消息
- **ISR 动态规则**：Follower 超过 `replica.lag.time.max.ms`（默认 10s）未追上 → 踢出 ISR
- **消息不丢三段配置**：
  - Producer: `acks=all` + `enable.idempotence=true`
  - Broker: `replication.factor=3` + `min.insync.replicas=2` + `unclean.leader.election.enable=false`
  - Consumer: `enable.auto.commit=false` + 业务后手动 `commitSync` + 业务幂等
- **无法 100% 保证**：CAP 权衡、网络异常、进程崩溃、副本全挂、事务超时——工程上没有 100%

## 关键结论

- **结论 A**：Kafka 副本一致性靠 **ISR + HW** 机制，Leader 挂只从 ISR 选新 Leader
- **结论 B**：消息可靠性靠"三段链路 + 关键参数"组合，光说"确认"、"落盘"不足以证明工程实践能力
- **结论 C**：Kafka 只能保证 **At-Least-Once**，不能保证 Exactly-Once（除非开 Kafka 事务 + 外部存储配合）
- **结论 D**：工程上没有 100% 可靠，能做的是把丢失概率降到足够低 + 兜底补偿

## 完整讲解（费曼四步）

### STEP 1 · 概念

**ISR（In-Sync Replicas）** 是分区中跟上 Leader 进度的副本子集；**消息可靠性**是指消息从 Producer 到 Consumer 全链路不丢失；**100% 边界**是 Kafka 的可靠性天花板。

### STEP 2 · 大白话

**银行多副本比喻**：
- Leader = 总行账本
- ISR = 各个分行账本，实时跟总行同步
- HW = "所有分行都同步到的最低一条记录"——客户只能查到 HW 之前的记录，因为之后的可能只有一部分分行有
- **unclean.leader.election** = 是否允许一个明显落后的分行当总行（会丢数据）

### STEP 3 · 底层

#### 副本三层概念

| 概念 | 全称 | 说明 |
|------|------|------|
| **AR** | Assigned Replicas | 分区的所有副本，静态（配置确定） |
| **ISR** | In-Sync Replicas | AR 中跟上 Leader 的副本，动态 |
| **OBR** | Out-of-Browser Replicas | AR - ISR，落后被踢的副本（2.4+ 术语） |

#### ISR 动态调整规则

- Follower 拉取消息超过 `replica.lag.time.max.ms`（默认 10s）没追上 Leader 的 LEO → 踢出 ISR
- 追上 Leader 后重新加入 ISR
- **时间维度**，不是 offset 落后多少条

#### HW 与 LEO

```
HW  = min(所有 ISR 副本的 LEO)
消费者只能读 HW 之前的消息
```

- 如果 ISR 只有 Leader 自己，HW = Leader 的 LEO
- LEO = 副本最后一条消息的下一个 offset

#### Leader 选举与故障转移

- Leader 挂掉 → Controller 从 **ISR** 中选新 Leader
- `unclean.leader.election.enable=true`：可从 OBR 选（**会丢数据**，生产不打开）
- `min.insync.replicas`：Producer `acks=all` 时至少需要多少 ISR 副本确认

#### 消息不丢三段链路配置

**Producer 端**：

| 参数 | 推荐值 | 说明 |
|------|-------|------|
| `acks` | `all` | 等所有 ISR 副本确认 |
| `retries` | `MAX_VALUE` | 无限重试 |
| `enable.idempotence` | `true` | 开启幂等，崩溃不重复 |
| `max.in.flight.requests.per.connection` | `5` | 幂等允许的最大值 |

**Broker 端**：

| 参数 | 推荐值 | 说明 |
|------|-------|------|
| `replication.factor` | `3` | 3 副本 |
| `min.insync.replicas` | `2` | 至少 2 副本确认 |
| `unclean.leader.election.enable` | `false` | 不允许非 ISR 当选 Leader |

**Consumer 端**：

| 参数 | 推荐值 | 说明 |
|------|-------|------|
| `enable.auto.commit` | `false` | 关闭自动提交 |
| 提交方式 | 业务后 `commitSync` | 手动提交 |
| 业务幂等 | 必做 | DB 唯一索引 / Redis / 去重表 |

#### 为什么无法 100% 保证消息不丢

**本质**：分布式系统 + 网络不可靠 + 硬件故障 + 进程崩溃，CAP 权衡

**三段链路丢失场景**：

| 环节 | 丢失场景 |
|------|---------|
| Producer | 应用崩溃（消息未发）/ 网络分区 / `acks=0` 时 Leader 挂 |
| Broker | ISR 收缩到 1 后 Leader 挂 / `unclean.leader.election=true` 数据回退 / 硬件故障 |
| Consumer | offset 提交但业务未完成 / 处理完成后 commit 前进程崩溃 / 反序列化失败 |
| 系统级 | ZooKeeper/KRaft Controller 故障 / 事务超时 abort |

**CAP 权衡**：
- Kafka 选择 AP（网络分区时可用优先）
- `unclean.leader.election=true` → 丢数据换可用
- `unclean.leader.election=false` → 不可用但不丢数据

#### At-Least-Once vs Exactly-Once

- **At-Least-Once**：Kafka 默认保证，可能重复消费，需要业务幂等
- **Exactly-Once**：需要 Kafka 事务 + `isolation.level=read_committed`，**只能保证 Kafka 内部** exactly-once，跨系统仍需外部存储配合

### STEP 4 · 简化

**一句话总结**：ISR 是副本一致性的核心；消息不丢靠"三段链路 + 关键参数"组合；Kafka 只能 At-Least-Once，100% 保证不存在。

**记忆口诀**：
- **副本**：AR ⊃ ISR ⊃ {Leader}，HW = min(所有 ISR LEO)
- **生产推荐**：acks=all + replication=3 + min.insync=2 + unclean=false + 手动 commit
- **100% 边界**：CAP 权衡，只能做到"概率足够低 + 兜底补偿"

## 常见误区

- **误区 1**：ISR 是"所有副本" → 正确：ISR 是**跟上 Leader 的动态子集**，AR 才是所有副本
- **误区 2**：ISR 落后多少条就踢出 → 正确：是**时间维度**（`replica.lag.time.max.ms`）
- **误区 3**：`unclean.leader.election=true` 是安全的 → 正确：会丢数据，生产**必须关闭**
- **误区 4**：Kafka 能保证 Exactly-Once → 正确：只能保证 **At-Least-Once**，Exactly-Once 需要事务且只限 Kafka 内部
- **误区 5**：`acks=1` 就够了 → 正确：Leader 挂时消息可能丢失；生产用 `acks=all` + `min.insync=2`
- **误区 6**：工程上可以做到 100% 保证不丢 → 正确：**不可能**，只能做到"概率足够低 + 兜底补偿"

## 延伸追问

1. **`min.insync.replicas=2` 但 ISR 只剩 1 个，会怎样？**
   - Producer 请求阻塞到 `request.timeout.ms`，业务侧报错；需扩容副本或临时降级。
2. **为什么 Kafka 选择 ISR 而不是 Raft 的多数派？**
   - ISR 用"追上"作为一致判断，简单高效；Raft 需要 term、votedfor、日志匹配，Kafka 复杂度更高收益不大。
3. **HW 会一直等于 LEO 吗？**
   - 正常时接近，Follower 挂掉时 HW 停滞，直到新副本追上。
4. **Kafka 事务能保证跨系统事务吗？**
   - 不能。只能保证 Kafka 内部 exactly-once，外部存储需要业务侧配合（本地消息表、SAGA）。
5. **如何设计"几乎不丢消息"的系统？**
   - Producer `acks=all` + `enable.idempotence=true`；Broker `replication.factor=3` + `min.insync=2` + `unclean=false`；Consumer 手动 commit + 业务幂等；外部存储用事务或最终一致性；再加对账机制。
6. **`unclean.leader.election.enable=true` 会带来什么后果？**
   - 可能选到落后的副本作为 Leader，已提交的消息可能被后续写入覆盖，数据丢失；生产上一般关闭。

## 速查表

```
副本: AR ⊃ ISR ⊃ {Leader}；OBR = AR - ISR
HW:   min(所有 ISR 副本的 LEO)，消费者只能读 HW 之前
踢出: replica.lag.time.max.ms（默认 10s）未追上 → 踢出 ISR
生产配置: acks=all + idempotence=true + replication=3 + min.insync=2 + unclean=false + 手动 commit + 业务幂等
100% 边界: CAP 权衡，无法 100%；只能 At-Least-Once（+ 业务幂等 = Exactly-Once 效果）
事务局限: Kafka 事务只保证 Kafka 内部 exactly-once，跨系统需外部配合
```

## 关联题目（题库）

- ⚠️ 《介绍一下 Kafka 的 ISR 机制？》— Round 2 Q6, 未作答
- ⚠️ 《Kafka 如何保证消息不丢失？》— Round 2 Q7, ⭐⭐⭐（框架对，漏具体参数）
- ✅ 《为什么 Kafka 没办法 100% 保证消息不丢失？》— Round 2 Q9, ⭐⭐⭐⭐（本轮最佳）

## 关联知识

- [Kafka 分区与性能](./kafka-partition-performance.md)
- [Kafka 事务消息](./kafka-transaction.md)
- [主题地图](./_moc.md)

## Anki 候选卡片

1. **正**：Kafka 副本三层概念？**反**：AR（所有副本）⊃ ISR（跟上 Leader）⊃ {Leader}；OBR = AR - ISR
2. **正**：HW（High Watermark）怎么算？**反**：HW = min(所有 ISR 副本的 LEO)，消费者只能读 HW 之前
3. **正**：ISR 踢出条件？**反**：Follower 超过 `replica.lag.time.max.ms`（默认 10s）未追上 Leader LEO
4. **正**：生产推荐的副本配置组合？**反**：`replication.factor=3` + `min.insync.replicas=2` + `unclean.leader.election.enable=false`
5. **正**：Kafka 能保证 Exactly-Once 吗？**反**：不能，只能 At-Least-Once；Exactly-Once 需要事务且只限 Kafka 内部
6. **正**：`unclean.leader.election.enable=true` 的后果？**反**：非 ISR 副本当选 Leader，可能覆盖已提交消息，数据丢失
7. **正**：为什么 Kafka 无法 100% 保证消息不丢？**反**：CAP 权衡、网络异常、进程崩溃、副本全挂、事务超时——工程上没有 100%
8. **正**：消息不丢的三段链路配置？**反**：Producer `acks=all` + `idempotence`；Broker `replication=3` + `min.insync=2`；Consumer 手动 commit + 业务幂等

---

*最后更新：2026-09-22*
