P96 Kafka 消息丢失的场景及解决方案
面试题:Kafka 消息在哪些环节会丢?怎么保证不丢?
1. 三个环节的丢失场景
① 生产端丢
acks=0:发出去不管,网络失败/服务端没收到就丢;acks=1:Leader 收到即确认,Leader 还没同步给副本就挂了 → 丢;- 发送失败没重试。
② 服务端(Broker)丢
- 副本数 = 1(没副本),节点挂了数据就丢;
- min.insync.replicas 配置不当:Leader 接收消息后 ISR 里没有其他副本,Leader 挂了数据丢;
- 磁盘故障、日志清理配置错误。
③ 消费端丢
- 先提交 offset 再处理业务:处理失败但 offset 已提交 → 消息被跳过(丢);
- 自动提交(enable.auto.commit=true)且处理耗时 > 提交间隔 → 处理中挂了,offset 已提交;
- 消费者异常退出导致再均衡,未处理完的消息丢失。
2. 解决方案
生产端
text
acks = all(或 -1)
retries 设置较大(如 3+)
enable.idempotence = true(幂等生产者,配合 acks=all)服务端
text
replication.factor >= 3(副本数)
min.insync.replicas >= 2(ISR 最小副本数)
unclean.leader.election.enable = false(不允许非同步副本当选 Leader)消费端
java
// 手动提交 offset:处理成功后再提交
props.put("enable.auto.commit", "false");
// 消费循环里
ConsumerRecords records = consumer.poll(...);
process(records); // 先处理
consumer.commitSync(); // 再提交3. 至少一次 vs 精确一次
- 上面配置保证 At Least Once(至少一次),可能重复消费;
- 要 Exactly Once:幂等生产者 + 事务(
initTransactions/beginTransaction/ 消费-处理-提交事务); - 或者消费端幂等(业务唯一键去重)。
4. 加分点
- 完整答法:生产 acks=all + 重试 + 幂等,服务端多副本 + min.insync,消费端先处理后提交 + 幂等;
- 追问"ack 和 ISR 的关系":acks=all 是等 ISR 全部确认;
- 提到"顺序保证"与"分区数变化"时可能乱序;
- 事故排查:看日志
Offset commit、Leader变更、生产端异常指标。
一句话总结
Kafka 不丢消息三端配合:生产端 acks=all + 重试 + 幂等,Broker 多副本 + min.insync.replicas + 禁 unclean 选举,消费端 处理成功再手动提交 offset + 业务幂等;代价是可能重复消费,靠幂等达到近似精确一次。