对于这个问题我个人的见解是:
首先,我们要搞清楚kafka保证消息不丢失的职责边界;
一句话概括,Kafka 只对已提交的消息做有限度的持久化保证。
第一个核心要素是“已提交的消息”。什么是已提交的消息?当 Kafka 的若干个 Broker 成功地接收到一条消息并写入到日志文件后,它们会告诉生产者程序这条消息已成功提交。此时,这条消息在 Kafka 看来就正式变为“已提交”消息了。
第二个核心要素就是“有限度的持久化保证”,也就是说 Kafka 不可能保证在任何情况下都做到不丢失消息。举个极端点的例子,如果地球都不存在了,Kafka 还能保存任何消息吗?显然不能!倘若这种情况下你依然还想要 Kafka 不丢消息,那么只能在别的星球部署 Kafka Broker 服务器了。
从这三方面入手:Producer → Broker → Consumer
Kafka 的无消息丢失不是单点配置,而是 Producer、Broker、Consumer 三端协同的结果。
Producer 端通过 acks=all 和幂等性确保消息成功写入多个副本;Broker 端通过副本机制、最小 ISR 和禁止不干净选举确保数据不丢;Consumer 端通过手动提交 Offset,确保消息被成功处理后才确认消费。
通过这套配置,可以在工程上实现高可靠的“无消息丢失”。
Producer 端:保证“消息一定成功写入 Kafka”
1️⃣ 必须开启 ACK 确认机制(核心)
acks=all
含义:
- Leader 写入成功
- 所有 ISR 副本写入成功
- Producer 才认为发送成功
❌ 如果用 acks=1 / 0
👉 Broker 宕机时直接丢消息
2️⃣ 开启重试(防网络抖动)
retries=Integer.MAX_VALUE
delivery.timeout.ms=120000
防止:
- 短暂网络失败
- Leader 切换
3️⃣ 开启幂等性(防重复 + 顺序)
enable.idempotence=true
作用:
- Producer 重试不会产生重复消息
- 保证单 Partition 内顺序
👉 这是无丢失配置的“必选项”
Broker 端:保证“消息不会写进去就没了”
1️⃣ 副本数 ≥ 2(生产通常 3)
replication.factor=3
原因:
- 1 副本 = 单点
- Broker 挂了直接丢
2️⃣ ISR 至少 2 个副本确认
min.insync.replicas=2
3️⃣ 禁止“不干净选举”(非常关键)
unclean.leader.election.enable=false
解释:
它控制的是哪些 Broker 有资格竞选分区的 Leader。如果一个 Broker 落后原先的 Leader 太多,那么它一旦成为新的 Leader,必然会造成消息的丢失。故一般都要将该参数设置成 false,即不允许这种情况的发生。
否则:
- 可能选一个没有完整数据的副本
- 历史消息直接丢失
Consumer 端:保证“消息一定被正确消费”
1️⃣ 关闭自动提交 Offset(重中之重)
enable.auto.commit=false
解释:书签的例子,先看完内容再更新书签,这里书签就好比Offset;这里除了把这个参数设置成false之外,并采用手动提交位移的方式。
否则:
- 先提交 Offset
- 再处理消息
- 程序崩了 → 消息永久丢失
2️⃣ 手动提交 Offset(在处理成功后)
process(record);
consumer.commitSync();
语义:
处理成功 → 才告诉 Kafka 我消费过了
总结:
## Producer 端标准配置:
acks=all
enable.idempotence=true
retries=Integer.MAX_VALUE
## Broker 端标准配置:
replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=false
## Consumer 端标准配置:
enable.auto.commit=false
| 组件 | 配置 | 目的 |
|---|---|---|
| Producer | acks=all | 写入确认 |
| Producer | enable.idempotence=true | 防重复 |
| Broker | replication.factor ≥ 3 | 副本冗余 |
| Broker | min.insync.replicas ≥ 2 | 写入安全 |
| Broker | unclean.leader.election=false | 不丢历史 |
| Consumer | enable.auto.commit=false | 防提前提交 |
踩坑:
❗ acks=all 就一定安全吗?
❌ 不够:
- ISR=1 时仍然危险
- 必须配合
min.insync.replicas