5月27日 22:10
Kafka 消息丢失的原因有哪些?怎么解决?
答案概览
Kafka 消息丢失发生在三个环节:Producer 发送端、Broker 存储端、Consumer 消费端。核心对策:Producer 配 acks=all + 重试,Broker 配多副本 + 禁脏选举,Consumer 关自动提交改手动确认。
Producer 端:消息发出去就丢了?
丢失原因:
acks=0或acks=1,Leader 写入成功就返回,Follower 还没同步 Leader 就挂了- 异步发送不带回调,发送失败无感知
retries未配置,网络抖动直接丢消息
解决方案:
propertiesacks=all retries=3 enable.idempotence=true max.in.flight.requests.per.connection=5
acks=all 要求所有 ISR 副本确认写入才算成功。enable.idempotence=true 开启幂等生产者,防止重试导致消息重复。注意:开启幂等性时 max.in.flight.requests.per.connection 需小于等于 5,否则幂等性失效。
用 producer.send(record, callback) 代替 producer.send(record),在回调里处理失败逻辑。
Broker 端:写进去了但读不到了?
丢失原因:
- 副本数只有 1,Broker 宕机直接丢数据
- Leader 崩溃后,未同步完的 Follower 被选为新 Leader(脏选举),未同步消息丢失
- 异步刷盘,数据还在 PageCache 没落盘就宕机
解决方案:
propertiesdefault.replication.factor=3 min.insync.replicas=2 unclean.leader.election.enable=false
replication.factor=3 保证三副本冗余。min.insync.replicas=2 要求至少 2 个副本在 ISR 中,否则 Producer 写入报错——宁可不可用也不丢数据。unclean.leader.election.enable=false 禁止落后副本参与选举,这是防丢的关键开关。
Consumer 端:消费了但白消费了?
丢失原因:
enable.auto.commit=true,消息拉取后自动提交 offset,但业务还没处理完就挂了,重启后这条消息不会再投递- 多线程消费时,处理慢的线程还没完成,offset 已被其他线程推进
解决方案:
propertiesenable.auto.commit=false
关闭自动提交,业务处理完成后手动调用 consumer.commitSync()。多线程场景下,每个线程维护自己的 offset,处理完再提交。
消费者还需实现幂等性:同一条消息可能被重复投递(rebalance 后),用唯一标识去重。
追问:acks=all 就一定不丢消息吗?
不一定。如果 ISR 中只剩 Leader 自己,acks=all 退化为 acks=1。所以 min.insync.replicas=2 必须配合使用——当 ISR 不足时拒绝写入,用可用性换可靠性。
配置速查
| 环节 | 关键配置 | 推荐值 |
|---|---|---|
| Producer | acks | all |
| Producer | retries | ≥3 |
| Producer | enable.idempotence | true |
| Broker | replication.factor | 3 |
| Broker | min.insync.replicas | 2 |
| Broker | unclean.leader.election.enable | false |
| Consumer | enable.auto.commit | false |